1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.intentresolver.profiles; 18 19 import android.content.Context; 20 import android.os.UserHandle; 21 import android.view.LayoutInflater; 22 import android.view.ViewGroup; 23 24 import androidx.recyclerview.widget.GridLayoutManager; 25 import androidx.recyclerview.widget.RecyclerView; 26 import androidx.viewpager.widget.PagerAdapter; 27 28 import com.android.intentresolver.ChooserListAdapter; 29 import com.android.intentresolver.ChooserRecyclerViewAccessibilityDelegate; 30 import com.android.intentresolver.R; 31 import com.android.intentresolver.emptystate.EmptyStateProvider; 32 import com.android.intentresolver.grid.ChooserGridAdapter; 33 import com.android.intentresolver.measurements.Tracer; 34 35 import com.google.common.collect.ImmutableList; 36 37 import java.util.Optional; 38 import java.util.function.Supplier; 39 40 /** 41 * A {@link PagerAdapter} which describes the work and personal profile share sheet screens. 42 */ 43 public class ChooserMultiProfilePagerAdapter extends MultiProfilePagerAdapter< 44 RecyclerView, ChooserGridAdapter, ChooserListAdapter> { 45 private static final int SINGLE_CELL_SPAN_SIZE = 1; 46 47 private final ChooserProfileAdapterBinder mAdapterBinder; 48 private final BottomPaddingOverrideSupplier mBottomPaddingOverrideSupplier; 49 ChooserMultiProfilePagerAdapter( Context context, ImmutableList<TabConfig<ChooserGridAdapter>> tabs, EmptyStateProvider emptyStateProvider, Supplier<Boolean> workProfileQuietModeChecker, @ProfileType int defaultProfile, UserHandle workProfileUserHandle, UserHandle cloneProfileUserHandle, int maxTargetsPerRow)50 public ChooserMultiProfilePagerAdapter( 51 Context context, 52 ImmutableList<TabConfig<ChooserGridAdapter>> tabs, 53 EmptyStateProvider emptyStateProvider, 54 Supplier<Boolean> workProfileQuietModeChecker, 55 @ProfileType int defaultProfile, 56 UserHandle workProfileUserHandle, 57 UserHandle cloneProfileUserHandle, 58 int maxTargetsPerRow) { 59 this( 60 context, 61 new ChooserProfileAdapterBinder(maxTargetsPerRow), 62 tabs, 63 emptyStateProvider, 64 workProfileQuietModeChecker, 65 defaultProfile, 66 workProfileUserHandle, 67 cloneProfileUserHandle, 68 new BottomPaddingOverrideSupplier(context)); 69 } 70 ChooserMultiProfilePagerAdapter( Context context, ChooserProfileAdapterBinder adapterBinder, ImmutableList<TabConfig<ChooserGridAdapter>> tabs, EmptyStateProvider emptyStateProvider, Supplier<Boolean> workProfileQuietModeChecker, @ProfileType int defaultProfile, UserHandle workProfileUserHandle, UserHandle cloneProfileUserHandle, BottomPaddingOverrideSupplier bottomPaddingOverrideSupplier)71 private ChooserMultiProfilePagerAdapter( 72 Context context, 73 ChooserProfileAdapterBinder adapterBinder, 74 ImmutableList<TabConfig<ChooserGridAdapter>> tabs, 75 EmptyStateProvider emptyStateProvider, 76 Supplier<Boolean> workProfileQuietModeChecker, 77 @ProfileType int defaultProfile, 78 UserHandle workProfileUserHandle, 79 UserHandle cloneProfileUserHandle, 80 BottomPaddingOverrideSupplier bottomPaddingOverrideSupplier) { 81 super( 82 gridAdapter -> gridAdapter.getListAdapter(), 83 adapterBinder, 84 tabs, 85 emptyStateProvider, 86 workProfileQuietModeChecker, 87 defaultProfile, 88 workProfileUserHandle, 89 cloneProfileUserHandle, 90 () -> makeProfileView(context), 91 bottomPaddingOverrideSupplier); 92 mAdapterBinder = adapterBinder; 93 mBottomPaddingOverrideSupplier = bottomPaddingOverrideSupplier; 94 } 95 setMaxTargetsPerRow(int maxTargetsPerRow)96 public void setMaxTargetsPerRow(int maxTargetsPerRow) { 97 mAdapterBinder.setMaxTargetsPerRow(maxTargetsPerRow); 98 } 99 setEmptyStateBottomOffset(int bottomOffset)100 public void setEmptyStateBottomOffset(int bottomOffset) { 101 mBottomPaddingOverrideSupplier.setEmptyStateBottomOffset(bottomOffset); 102 setupContainerPadding(); 103 } 104 105 /** 106 * Notify adapter about the drawer's collapse state. This will affect the app divider's 107 * visibility. 108 */ setIsCollapsed(boolean isCollapsed)109 public void setIsCollapsed(boolean isCollapsed) { 110 for (int i = 0, size = getItemCount(); i < size; i++) { 111 getPageAdapterForIndex(i).setAzLabelVisibility(!isCollapsed); 112 } 113 } 114 makeProfileView(Context context)115 private static ViewGroup makeProfileView(Context context) { 116 LayoutInflater inflater = LayoutInflater.from(context); 117 ViewGroup rootView = 118 (ViewGroup) inflater.inflate(R.layout.chooser_list_per_profile_wrap, null, false); 119 RecyclerView recyclerView = rootView.findViewById(com.android.internal.R.id.resolver_list); 120 recyclerView.setAccessibilityDelegateCompat( 121 new ChooserRecyclerViewAccessibilityDelegate(recyclerView)); 122 return rootView; 123 } 124 125 @Override onHandlePackagesChanged( ChooserListAdapter listAdapter, boolean waitingToEnableWorkProfile)126 public boolean onHandlePackagesChanged( 127 ChooserListAdapter listAdapter, boolean waitingToEnableWorkProfile) { 128 // TODO: why do we need to do the extra `notifyDataSetChanged()` in (only) the Chooser case? 129 getActiveListAdapter().notifyDataSetChanged(); 130 return super.onHandlePackagesChanged(listAdapter, waitingToEnableWorkProfile); 131 } 132 133 @Override rebuildTab(ChooserListAdapter listAdapter, boolean doPostProcessing)134 protected final boolean rebuildTab(ChooserListAdapter listAdapter, boolean doPostProcessing) { 135 if (doPostProcessing) { 136 Tracer.INSTANCE.beginAppTargetLoadingSection(listAdapter.getUserHandle()); 137 } 138 return super.rebuildTab(listAdapter, doPostProcessing); 139 } 140 141 /** Apply the specified {@code height} as the footer in each tab's adapter. */ setFooterHeightInEveryAdapter(int height)142 public void setFooterHeightInEveryAdapter(int height) { 143 for (int i = 0; i < getItemCount(); ++i) { 144 getPageAdapterForIndex(i).setFooterHeight(height); 145 } 146 } 147 148 /** Cleanup system resources */ destroy()149 public void destroy() { 150 for (int i = 0, count = getItemCount(); i < count; i++) { 151 ChooserGridAdapter adapter = getPageAdapterForIndex(i); 152 if (adapter != null) { 153 adapter.getListAdapter().onDestroy(); 154 } 155 } 156 } 157 158 private static class BottomPaddingOverrideSupplier implements Supplier<Optional<Integer>> { 159 private final Context mContext; 160 private int mBottomOffset; 161 BottomPaddingOverrideSupplier(Context context)162 BottomPaddingOverrideSupplier(Context context) { 163 mContext = context; 164 } 165 setEmptyStateBottomOffset(int bottomOffset)166 public void setEmptyStateBottomOffset(int bottomOffset) { 167 mBottomOffset = bottomOffset; 168 } 169 170 @Override get()171 public Optional<Integer> get() { 172 int initialBottomPadding = mContext.getResources().getDimensionPixelSize( 173 R.dimen.resolver_empty_state_container_padding_bottom); 174 return Optional.of(initialBottomPadding + mBottomOffset); 175 } 176 } 177 178 private static class ChooserProfileAdapterBinder implements 179 AdapterBinder<RecyclerView, ChooserGridAdapter> { 180 private int mMaxTargetsPerRow; 181 ChooserProfileAdapterBinder(int maxTargetsPerRow)182 ChooserProfileAdapterBinder(int maxTargetsPerRow) { 183 mMaxTargetsPerRow = maxTargetsPerRow; 184 } 185 setMaxTargetsPerRow(int maxTargetsPerRow)186 public void setMaxTargetsPerRow(int maxTargetsPerRow) { 187 mMaxTargetsPerRow = maxTargetsPerRow; 188 } 189 190 @Override bind( RecyclerView recyclerView, ChooserGridAdapter chooserGridAdapter)191 public void bind( 192 RecyclerView recyclerView, ChooserGridAdapter chooserGridAdapter) { 193 GridLayoutManager glm = (GridLayoutManager) recyclerView.getLayoutManager(); 194 glm.setSpanCount(mMaxTargetsPerRow); 195 glm.setSpanSizeLookup( 196 new GridLayoutManager.SpanSizeLookup() { 197 @Override 198 public int getSpanSize(int position) { 199 return chooserGridAdapter.shouldCellSpan(position) 200 ? SINGLE_CELL_SPAN_SIZE 201 : glm.getSpanCount(); 202 } 203 }); 204 } 205 } 206 } 207