• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static com.android.intentresolver.Flags.keyboardNavigationFix;
20 
21 import android.content.Context;
22 import android.os.UserHandle;
23 import android.view.LayoutInflater;
24 import android.view.ViewGroup;
25 
26 import androidx.recyclerview.widget.GridLayoutManager;
27 import androidx.recyclerview.widget.RecyclerView;
28 import androidx.viewpager.widget.PagerAdapter;
29 
30 import com.android.intentresolver.ChooserListAdapter;
31 import com.android.intentresolver.ChooserRecyclerViewAccessibilityDelegate;
32 import com.android.intentresolver.R;
33 import com.android.intentresolver.emptystate.EmptyStateProvider;
34 import com.android.intentresolver.grid.ChooserGridAdapter;
35 import com.android.intentresolver.measurements.Tracer;
36 
37 import com.google.common.collect.ImmutableList;
38 
39 import java.util.Optional;
40 import java.util.function.Supplier;
41 
42 /**
43  * A {@link PagerAdapter} which describes the work and personal profile share sheet screens.
44  */
45 public class ChooserMultiProfilePagerAdapter extends MultiProfilePagerAdapter<
46         RecyclerView, ChooserGridAdapter, ChooserListAdapter> {
47     private static final int SINGLE_CELL_SPAN_SIZE = 1;
48 
49     private final ChooserProfileAdapterBinder mAdapterBinder;
50     private final BottomPaddingOverrideSupplier mBottomPaddingOverrideSupplier;
51 
ChooserMultiProfilePagerAdapter( Context context, ImmutableList<TabConfig<ChooserGridAdapter>> tabs, EmptyStateProvider emptyStateProvider, Supplier<Boolean> workProfileQuietModeChecker, @ProfileType int defaultProfile, UserHandle workProfileUserHandle, UserHandle cloneProfileUserHandle, int maxTargetsPerRow)52     public ChooserMultiProfilePagerAdapter(
53             Context context,
54             ImmutableList<TabConfig<ChooserGridAdapter>> tabs,
55             EmptyStateProvider emptyStateProvider,
56             Supplier<Boolean> workProfileQuietModeChecker,
57             @ProfileType int defaultProfile,
58             UserHandle workProfileUserHandle,
59             UserHandle cloneProfileUserHandle,
60             int maxTargetsPerRow) {
61         this(
62                 context,
63                 new ChooserProfileAdapterBinder(maxTargetsPerRow),
64                 tabs,
65                 emptyStateProvider,
66                 workProfileQuietModeChecker,
67                 defaultProfile,
68                 workProfileUserHandle,
69                 cloneProfileUserHandle,
70                 new BottomPaddingOverrideSupplier(context));
71     }
72 
ChooserMultiProfilePagerAdapter( Context context, ChooserProfileAdapterBinder adapterBinder, ImmutableList<TabConfig<ChooserGridAdapter>> tabs, EmptyStateProvider emptyStateProvider, Supplier<Boolean> workProfileQuietModeChecker, @ProfileType int defaultProfile, UserHandle workProfileUserHandle, UserHandle cloneProfileUserHandle, BottomPaddingOverrideSupplier bottomPaddingOverrideSupplier)73     private ChooserMultiProfilePagerAdapter(
74             Context context,
75             ChooserProfileAdapterBinder adapterBinder,
76             ImmutableList<TabConfig<ChooserGridAdapter>> tabs,
77             EmptyStateProvider emptyStateProvider,
78             Supplier<Boolean> workProfileQuietModeChecker,
79             @ProfileType int defaultProfile,
80             UserHandle workProfileUserHandle,
81             UserHandle cloneProfileUserHandle,
82             BottomPaddingOverrideSupplier bottomPaddingOverrideSupplier) {
83         super(
84                 gridAdapter -> gridAdapter.getListAdapter(),
85                 adapterBinder,
86                 tabs,
87                 emptyStateProvider,
88                 workProfileQuietModeChecker,
89                 defaultProfile,
90                 workProfileUserHandle,
91                 cloneProfileUserHandle,
92                 () -> makeProfileView(context),
93                 bottomPaddingOverrideSupplier);
94         mAdapterBinder = adapterBinder;
95         mBottomPaddingOverrideSupplier = bottomPaddingOverrideSupplier;
96     }
97 
setMaxTargetsPerRow(int maxTargetsPerRow)98     public void setMaxTargetsPerRow(int maxTargetsPerRow) {
99         mAdapterBinder.setMaxTargetsPerRow(maxTargetsPerRow);
100     }
101 
setEmptyStateBottomOffset(int bottomOffset)102     public void setEmptyStateBottomOffset(int bottomOffset) {
103         mBottomPaddingOverrideSupplier.setEmptyStateBottomOffset(bottomOffset);
104         setupContainerPadding();
105     }
106 
107     /**
108      * Notify adapter about the drawer's collapse state. This will affect the app divider's
109      * visibility.
110      */
setIsCollapsed(boolean isCollapsed)111     public void setIsCollapsed(boolean isCollapsed) {
112         for (int i = 0, size = getItemCount(); i < size; i++) {
113             getPageAdapterForIndex(i).setAzLabelVisibility(!isCollapsed);
114         }
115     }
116 
117     /**
118      * Set enabled status for all targets in all profiles.
119      */
setTargetsEnabled(boolean isEnabled)120     public void setTargetsEnabled(boolean isEnabled) {
121         for (int i = 0, size = getItemCount(); i < size; i++) {
122             getPageAdapterForIndex(i).getListAdapter().setTargetsEnabled(isEnabled);
123         }
124     }
125 
makeProfileView(Context context)126     private static ViewGroup makeProfileView(Context context) {
127         LayoutInflater inflater = LayoutInflater.from(context);
128         ViewGroup rootView =
129                 (ViewGroup) inflater.inflate(R.layout.chooser_list_per_profile_wrap, null, false);
130         if (!keyboardNavigationFix()) {
131             rootView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
132         }
133         RecyclerView recyclerView = rootView.findViewById(com.android.internal.R.id.resolver_list);
134         recyclerView.setAccessibilityDelegateCompat(
135                 new ChooserRecyclerViewAccessibilityDelegate(recyclerView));
136         return rootView;
137     }
138 
139     @Override
onHandlePackagesChanged( ChooserListAdapter listAdapter, boolean waitingToEnableWorkProfile)140     public boolean onHandlePackagesChanged(
141             ChooserListAdapter listAdapter, boolean waitingToEnableWorkProfile) {
142         // TODO: why do we need to do the extra `notifyDataSetChanged()` in (only) the Chooser case?
143         getActiveListAdapter().notifyDataSetChanged();
144         return super.onHandlePackagesChanged(listAdapter, waitingToEnableWorkProfile);
145     }
146 
147     @Override
rebuildTab(ChooserListAdapter listAdapter, boolean doPostProcessing)148     protected final boolean rebuildTab(ChooserListAdapter listAdapter, boolean doPostProcessing) {
149         if (doPostProcessing) {
150             Tracer.INSTANCE.beginAppTargetLoadingSection(listAdapter.getUserHandle());
151         }
152         return super.rebuildTab(listAdapter, doPostProcessing);
153     }
154 
155     /** Apply the specified {@code height} as the footer in each tab's adapter. */
setFooterHeightInEveryAdapter(int height)156     public void setFooterHeightInEveryAdapter(int height) {
157         for (int i = 0; i < getItemCount(); ++i) {
158             getPageAdapterForIndex(i).setFooterHeight(height);
159         }
160     }
161 
162     /** Cleanup system resources */
destroy()163     public void destroy() {
164         for (int i = 0, count = getItemCount(); i < count; i++) {
165             ChooserGridAdapter adapter = getPageAdapterForIndex(i);
166             if (adapter != null) {
167                 adapter.getListAdapter().onDestroy();
168             }
169         }
170     }
171 
172     private static class BottomPaddingOverrideSupplier implements Supplier<Optional<Integer>> {
173         private final Context mContext;
174         private int mBottomOffset;
175 
BottomPaddingOverrideSupplier(Context context)176         BottomPaddingOverrideSupplier(Context context) {
177             mContext = context;
178         }
179 
setEmptyStateBottomOffset(int bottomOffset)180         public void setEmptyStateBottomOffset(int bottomOffset) {
181             mBottomOffset = bottomOffset;
182         }
183 
184         @Override
get()185         public Optional<Integer> get() {
186             int initialBottomPadding = mContext.getResources().getDimensionPixelSize(
187                     R.dimen.resolver_empty_state_container_padding_bottom);
188             return Optional.of(initialBottomPadding + mBottomOffset);
189         }
190     }
191 
192     private static class ChooserProfileAdapterBinder implements
193             AdapterBinder<RecyclerView, ChooserGridAdapter> {
194         private int mMaxTargetsPerRow;
195 
ChooserProfileAdapterBinder(int maxTargetsPerRow)196         ChooserProfileAdapterBinder(int maxTargetsPerRow) {
197             mMaxTargetsPerRow = maxTargetsPerRow;
198         }
199 
setMaxTargetsPerRow(int maxTargetsPerRow)200         public void setMaxTargetsPerRow(int maxTargetsPerRow) {
201             mMaxTargetsPerRow = maxTargetsPerRow;
202         }
203 
204         @Override
bind( RecyclerView recyclerView, ChooserGridAdapter chooserGridAdapter)205         public void bind(
206                 RecyclerView recyclerView, ChooserGridAdapter chooserGridAdapter) {
207             GridLayoutManager glm = (GridLayoutManager) recyclerView.getLayoutManager();
208             glm.setSpanCount(mMaxTargetsPerRow);
209             glm.setSpanSizeLookup(
210                     new GridLayoutManager.SpanSizeLookup() {
211                         @Override
212                         public int getSpanSize(int position) {
213                             return chooserGridAdapter.shouldCellSpan(position)
214                                     ? SINGLE_CELL_SPAN_SIZE
215                                     : glm.getSpanCount();
216                         }
217                     });
218         }
219     }
220 }
221