diff options
| author | 2023-12-19 22:36:59 +0000 | |
|---|---|---|
| committer | 2024-01-05 18:06:59 +0000 | |
| commit | 6cf3e38519ef4704b14e8ac3f94ea651fa309f68 (patch) | |
| tree | b34c2b20724181bf57f0b360796b4ce81fde2ba1 /java/src | |
| parent | af6a22081dca5b68e99af1cd6127bae660651565 (diff) | |
Generalize pager-adapter to support "many" tabs
(as in "0-1-many": if we have to support "multiple" then we shouldn't
hard-code limitations on the number that we *do* support.)
These changes are as prototyped in ag/25335069 and described in
go/chooser-ntab-refactoring, in particular replicating the changes of
"snapshot 34" through "snapshot 36." See below for a "by-snapshot"
breakdown of the incremental changes composed in this CL.
Snapshot 1: build pager-adapters from requests that include enough
details about the pages for us to be able to implement
`setupProfileTabs()` from our own records, without requiring the
caller to provide per-tab data. This change stops short of actually
changing the implementation of `setupProfileTabs()` and mostly just
establishes the bookkeeping / new convention for configuration.
Snapshot 2: implement `MultiProfilePagerAdapter.setupProfileTabs()` to
build tabs from its own records.
Snapshot 3: look up the page number for the "default profile" page,
instead of assuming it's equal to the profile ID (since that may not
be true in the "n-tab" case).
Bug: 310211468
Test: `IntentResolver-tests-{activity,unit}`, `ResolverActivityTest`
Change-Id: I3f8b9f9e53ff7a0740d1accd3a50b08e7c01bb55
Diffstat (limited to 'java/src')
5 files changed, 169 insertions, 83 deletions
diff --git a/java/src/com/android/intentresolver/v2/ChooserActivity.java b/java/src/com/android/intentresolver/v2/ChooserActivity.java index 2e020743..25024799 100644 --- a/java/src/com/android/intentresolver/v2/ChooserActivity.java +++ b/java/src/com/android/intentresolver/v2/ChooserActivity.java @@ -1164,12 +1164,6 @@ public class ChooserActivity extends Hilt_ChooserActivity implements viewPager, R.layout.resolver_profile_tab_button, com.android.internal.R.id.profile_pager, - mDevicePolicyResources.getPersonalTabLabel(), - mDevicePolicyResources.getPersonalTabAccessibilityLabel(), - TAB_TAG_PERSONAL, - mDevicePolicyResources.getWorkTabLabel(), - mDevicePolicyResources.getWorkTabAccessibilityLabel(), - TAB_TAG_WORK, () -> onProfileTabSelected(viewPager.getCurrentItem()), new MultiProfilePagerAdapter.OnProfileSelectedListener() { @Override @@ -1338,6 +1332,9 @@ public class ChooserActivity extends Hilt_ChooserActivity implements targetDataLoader); return new ChooserMultiProfilePagerAdapter( /* context */ this, + mDevicePolicyResources.getPersonalTabLabel(), + mDevicePolicyResources.getPersonalTabAccessibilityLabel(), + TAB_TAG_PERSONAL, adapter, createEmptyStateProvider(/* workProfileUserHandle= */ null), /* workProfileQuietModeChecker= */ () -> false, @@ -1371,7 +1368,13 @@ public class ChooserActivity extends Hilt_ChooserActivity implements targetDataLoader); return new ChooserMultiProfilePagerAdapter( /* context */ this, + mDevicePolicyResources.getPersonalTabLabel(), + mDevicePolicyResources.getPersonalTabAccessibilityLabel(), + TAB_TAG_PERSONAL, personalAdapter, + mDevicePolicyResources.getWorkTabLabel(), + mDevicePolicyResources.getWorkTabAccessibilityLabel(), + TAB_TAG_WORK, workAdapter, createEmptyStateProvider(requireAnnotatedUserHandles().workProfileUserHandle), () -> mLogic.getWorkProfileAvailabilityManager().isQuietModeEnabled(), diff --git a/java/src/com/android/intentresolver/v2/ChooserMultiProfilePagerAdapter.java b/java/src/com/android/intentresolver/v2/ChooserMultiProfilePagerAdapter.java index c3db4a51..14532b67 100644 --- a/java/src/com/android/intentresolver/v2/ChooserMultiProfilePagerAdapter.java +++ b/java/src/com/android/intentresolver/v2/ChooserMultiProfilePagerAdapter.java @@ -50,7 +50,10 @@ public class ChooserMultiProfilePagerAdapter extends MultiProfilePagerAdapter< public ChooserMultiProfilePagerAdapter( Context context, - ChooserGridAdapter adapter, + String personalTabLabel, + String personalTabAccessibilityLabel, + String personalTabTag, + ChooserGridAdapter personalAdapter, EmptyStateProvider emptyStateProvider, Supplier<Boolean> workProfileQuietModeChecker, UserHandle workProfileUserHandle, @@ -60,7 +63,13 @@ public class ChooserMultiProfilePagerAdapter extends MultiProfilePagerAdapter< this( context, new ChooserProfileAdapterBinder(maxTargetsPerRow), - ImmutableList.of(adapter), + ImmutableList.of( + new TabConfig<>( + PROFILE_PERSONAL, + personalTabLabel, + personalTabAccessibilityLabel, + personalTabTag, + personalAdapter)), emptyStateProvider, workProfileQuietModeChecker, /* defaultProfile= */ 0, @@ -72,7 +81,13 @@ public class ChooserMultiProfilePagerAdapter extends MultiProfilePagerAdapter< public ChooserMultiProfilePagerAdapter( Context context, + String personalTabLabel, + String personalTabAccessibilityLabel, + String personalTabTag, ChooserGridAdapter personalAdapter, + String workTabLabel, + String workTabAccessibilityLabel, + String workTabTag, ChooserGridAdapter workAdapter, EmptyStateProvider emptyStateProvider, Supplier<Boolean> workProfileQuietModeChecker, @@ -84,7 +99,19 @@ public class ChooserMultiProfilePagerAdapter extends MultiProfilePagerAdapter< this( context, new ChooserProfileAdapterBinder(maxTargetsPerRow), - ImmutableList.of(personalAdapter, workAdapter), + ImmutableList.of( + new TabConfig<>( + PROFILE_PERSONAL, + personalTabLabel, + personalTabAccessibilityLabel, + personalTabTag, + personalAdapter), + new TabConfig<>( + PROFILE_WORK, + workTabLabel, + workTabAccessibilityLabel, + workTabTag, + workAdapter)), emptyStateProvider, workProfileQuietModeChecker, defaultProfile, @@ -97,7 +124,7 @@ public class ChooserMultiProfilePagerAdapter extends MultiProfilePagerAdapter< private ChooserMultiProfilePagerAdapter( Context context, ChooserProfileAdapterBinder adapterBinder, - ImmutableList<ChooserGridAdapter> gridAdapters, + ImmutableList<TabConfig<ChooserGridAdapter>> tabs, EmptyStateProvider emptyStateProvider, Supplier<Boolean> workProfileQuietModeChecker, @Profile int defaultProfile, @@ -108,7 +135,7 @@ public class ChooserMultiProfilePagerAdapter extends MultiProfilePagerAdapter< super( gridAdapter -> gridAdapter.getListAdapter(), adapterBinder, - gridAdapters, + tabs, emptyStateProvider, workProfileQuietModeChecker, defaultProfile, diff --git a/java/src/com/android/intentresolver/v2/MultiProfilePagerAdapter.java b/java/src/com/android/intentresolver/v2/MultiProfilePagerAdapter.java index 3f772775..2883542e 100644 --- a/java/src/com/android/intentresolver/v2/MultiProfilePagerAdapter.java +++ b/java/src/com/android/intentresolver/v2/MultiProfilePagerAdapter.java @@ -38,6 +38,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import java.util.HashSet; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; @@ -109,10 +110,31 @@ class MultiProfilePagerAdapter< private int mCurrentPage; private OnProfileSelectedListener mOnProfileSelectedListener; + public static class TabConfig<PageAdapterT> { + private final @Profile int mProfile; + private final String mTabLabel; + private final String mTabAccessibilityLabel; + private final String mTabTag; + private final PageAdapterT mPageAdapter; + + public TabConfig( + @Profile int profile, + String tabLabel, + String tabAccessibilityLabel, + String tabTag, + PageAdapterT pageAdapter) { + mProfile = profile; + mTabLabel = tabLabel; + mTabAccessibilityLabel = tabAccessibilityLabel; + mTabTag = tabTag; + mPageAdapter = pageAdapter; + } + } + protected MultiProfilePagerAdapter( Function<SinglePageAdapterT, ListAdapterT> listAdapterExtractor, AdapterBinder<PageViewT, SinglePageAdapterT> adapterBinder, - ImmutableList<SinglePageAdapterT> adapters, + ImmutableList<TabConfig<SinglePageAdapterT>> tabs, EmptyStateProvider emptyStateProvider, Supplier<Boolean> workProfileQuietModeChecker, @Profile int defaultProfile, @@ -120,7 +142,6 @@ class MultiProfilePagerAdapter< UserHandle cloneProfileUserHandle, Supplier<ViewGroup> pageViewInflater, Supplier<Optional<Integer>> containerBottomPaddingOverrideSupplier) { - mCurrentPage = defaultProfile; mLoadedPages = new HashSet<>(); mWorkProfileUserHandle = workProfileUserHandle; mCloneProfileUserHandle = cloneProfileUserHandle; @@ -133,38 +154,40 @@ class MultiProfilePagerAdapter< ImmutableList.Builder<ProfileDescriptor<PageViewT, SinglePageAdapterT>> items = new ImmutableList.Builder<>(); - // TODO: for now this only builds in personal and work tabs; any other provided `adapters` - // are ignored. Historically this class wouldn't have behaved correctly for any more than - // those two tabs, so this is more explicit about our current support. Upcoming changes will - // generalize to support more tabs. - for (SinglePageAdapterT pageAdapter : adapters) { - ListAdapterT listAdapter = mListAdapterExtractor.apply(pageAdapter); - if (listAdapter.getUserHandle().equals(workProfileUserHandle)) { - items.add( - createProfileDescriptor( - PROFILE_WORK, pageAdapter, containerBottomPaddingOverrideSupplier)); - } else { - // TODO: it shouldn't be possible to add multiple "personal" descriptors. For now - // we're just trusting our clients to provide valid data. We should avoid making - // inferences from the adapter's user handle, and instead have the pager-adapter - // receive all the necessary configuration data (in some format that ensures - // uniqueness of the adapters assigned to a given profile). - items.add( - createProfileDescriptor( - PROFILE_PERSONAL, - pageAdapter, - containerBottomPaddingOverrideSupplier)); - } + for (TabConfig<SinglePageAdapterT> tab : tabs) { + // TODO: consider representing tabConfig in a different data structure that can ensure + // uniqueness of their profile assignments (while still respecting the client's + // requested tab order). + items.add( + createProfileDescriptor( + tab.mProfile, + tab.mTabLabel, + tab.mTabAccessibilityLabel, + tab.mTabTag, + tab.mPageAdapter, + containerBottomPaddingOverrideSupplier)); } mItems = items.build(); + + mCurrentPage = + hasPageForProfile(defaultProfile) ? getPageNumberForProfile(defaultProfile) : 0; } private ProfileDescriptor<PageViewT, SinglePageAdapterT> createProfileDescriptor( @Profile int profile, + String tabLabel, + String tabAccessibilityLabel, + String tabTag, SinglePageAdapterT adapter, Supplier<Optional<Integer>> containerBottomPaddingOverrideSupplier) { return new ProfileDescriptor<>( - profile, mPageViewInflater.get(), adapter, containerBottomPaddingOverrideSupplier); + profile, + tabLabel, + tabAccessibilityLabel, + tabTag, + mPageViewInflater.get(), + adapter, + containerBottomPaddingOverrideSupplier); } private boolean hasPageForIndex(int pageIndex) { @@ -241,6 +264,15 @@ class MultiProfilePagerAdapter< return getItem(getPageNumberForUserHandle(userHandle)); } + private int getPageNumberForTabTag(String tag) { + for (int i = 0; i < mItems.size(); ++i) { + if (Objects.equals(mItems.get(i).mTabTag, tag)) { + return i; + } + } + return -1; + } + private void updateActiveTabStyle(TabHost tabHost) { int currentTab = tabHost.getCurrentTab(); @@ -258,48 +290,34 @@ class MultiProfilePagerAdapter< ViewPager viewPager, int tabButtonLayoutResId, int tabPageContentViewId, - String personalTabLabel, - String personalTabAccessibilityLabel, - String personalTabTag, - String workTabLabel, - String workTabAccessibilityLabel, - String workTabTag, Runnable onTabChangeListener, MultiProfilePagerAdapter.OnProfileSelectedListener clientOnProfileSelectedListener) { tabHost.setup(); viewPager.setSaveEnabled(false); - Button personalButton = (Button) layoutInflater.inflate( - tabButtonLayoutResId, tabHost.getTabWidget(), false); - personalButton.setText(personalTabLabel); - personalButton.setContentDescription(personalTabAccessibilityLabel); - - TabHost.TabSpec personalTabSpec = tabHost.newTabSpec(personalTabTag) - .setContent(tabPageContentViewId) - .setIndicator(personalButton); - tabHost.addTab(personalTabSpec); - - Button workButton = (Button) layoutInflater.inflate( - tabButtonLayoutResId, tabHost.getTabWidget(), false); - workButton.setText(workTabLabel); - workButton.setContentDescription(workTabAccessibilityLabel); - - TabHost.TabSpec workTabSpec = tabHost.newTabSpec(workTabTag) - .setContent(tabPageContentViewId) - .setIndicator(workButton); - tabHost.addTab(workTabSpec); + for (int pageNumber = 0; pageNumber < getItemCount(); ++pageNumber) { + ProfileDescriptor<PageViewT, SinglePageAdapterT> descriptor = mItems.get(pageNumber); + Button profileButton = (Button) layoutInflater.inflate( + tabButtonLayoutResId, tabHost.getTabWidget(), false); + profileButton.setText(descriptor.mTabLabel); + profileButton.setContentDescription(descriptor.mTabAccessibilityLabel); + + TabHost.TabSpec profileTabSpec = tabHost.newTabSpec(descriptor.mTabTag) + .setContent(tabPageContentViewId) + .setIndicator(profileButton); + tabHost.addTab(profileTabSpec); + } tabHost.getTabWidget().setVisibility(View.VISIBLE); updateActiveTabStyle(tabHost); - tabHost.setOnTabChangedListener(tabId -> { + tabHost.setOnTabChangedListener(tabTag -> { updateActiveTabStyle(tabHost); - // TODO: update for 3+ tabs. - if (personalTabTag.equals(tabId)) { - viewPager.setCurrentItem(0); - } else { - viewPager.setCurrentItem(1); + + int pageNumber = getPageNumberForTabTag(tabTag); + if (pageNumber >= 0) { + viewPager.setCurrentItem(pageNumber); } onTabChangeListener.run(); }); @@ -736,6 +754,9 @@ class MultiProfilePagerAdapter< // should be the owner of all per-profile data (especially now that the API is generic)? private static class ProfileDescriptor<PageViewT, SinglePageAdapterT> { final @Profile int mProfile; + final String mTabLabel; + final String mTabAccessibilityLabel; + final String mTabTag; final ViewGroup mRootView; final EmptyStateUiHelper mEmptyStateUi; @@ -749,10 +770,16 @@ class MultiProfilePagerAdapter< ProfileDescriptor( @Profile int forProfile, + String tabLabel, + String tabAccessibilityLabel, + String tabTag, ViewGroup rootView, SinglePageAdapterT adapter, Supplier<Optional<Integer>> containerBottomPaddingOverrideSupplier) { mProfile = forProfile; + mTabLabel = tabLabel; + mTabAccessibilityLabel = tabAccessibilityLabel; + mTabTag = tabTag; mRootView = rootView; mAdapter = adapter; mEmptyStateView = rootView.findViewById(com.android.internal.R.id.resolver_empty_state); diff --git a/java/src/com/android/intentresolver/v2/ResolverActivity.java b/java/src/com/android/intentresolver/v2/ResolverActivity.java index 2a6ed9d5..3394c543 100644 --- a/java/src/com/android/intentresolver/v2/ResolverActivity.java +++ b/java/src/com/android/intentresolver/v2/ResolverActivity.java @@ -167,8 +167,8 @@ public class ResolverActivity extends Hilt_ResolverActivity implements /** Tracks if we should ignore future broadcasts telling us the work profile is enabled */ private final boolean mWorkProfileHasBeenEnabled = false; - private static final String TAB_TAG_PERSONAL = "personal"; - private static final String TAB_TAG_WORK = "work"; + protected static final String TAB_TAG_PERSONAL = "personal"; + protected static final String TAB_TAG_WORK = "work"; private PackageMonitor mPersonalPackageMonitor; private PackageMonitor mWorkPackageMonitor; @@ -946,7 +946,7 @@ public class ResolverActivity extends Hilt_ResolverActivity implements List<ResolveInfo> resolutionList, boolean filterLastUsed, TargetDataLoader targetDataLoader) { - ResolverListAdapter adapter = createResolverListAdapter( + ResolverListAdapter personalAdapter = createResolverListAdapter( /* context */ this, mLogic.getPayloadIntents(), initialIntents, @@ -956,7 +956,10 @@ public class ResolverActivity extends Hilt_ResolverActivity implements targetDataLoader); return new ResolverMultiProfilePagerAdapter( /* context */ this, - adapter, + mDevicePolicyResources.getPersonalTabLabel(), + mDevicePolicyResources.getPersonalTabAccessibilityLabel(), + TAB_TAG_PERSONAL, + personalAdapter, createEmptyStateProvider(/* workProfileUserHandle= */ null), /* workProfileQuietModeChecker= */ () -> false, /* workProfileUserHandle= */ null, @@ -1015,7 +1018,13 @@ public class ResolverActivity extends Hilt_ResolverActivity implements targetDataLoader); return new ResolverMultiProfilePagerAdapter( /* context */ this, + mDevicePolicyResources.getPersonalTabLabel(), + mDevicePolicyResources.getPersonalTabAccessibilityLabel(), + TAB_TAG_PERSONAL, personalAdapter, + mDevicePolicyResources.getWorkTabLabel(), + mDevicePolicyResources.getWorkTabAccessibilityLabel(), + TAB_TAG_WORK, workAdapter, createEmptyStateProvider(workProfileUserHandle), () -> mLogic.getWorkProfileAvailabilityManager().isQuietModeEnabled(), @@ -1904,12 +1913,6 @@ public class ResolverActivity extends Hilt_ResolverActivity implements viewPager, R.layout.resolver_profile_tab_button, com.android.internal.R.id.profile_pager, - mDevicePolicyResources.getPersonalTabLabel(), - mDevicePolicyResources.getPersonalTabAccessibilityLabel(), - TAB_TAG_PERSONAL, - mDevicePolicyResources.getWorkTabLabel(), - mDevicePolicyResources.getWorkTabAccessibilityLabel(), - TAB_TAG_WORK, () -> onProfileTabSelected(viewPager.getCurrentItem()), new MultiProfilePagerAdapter.OnProfileSelectedListener() { @Override diff --git a/java/src/com/android/intentresolver/v2/ResolverMultiProfilePagerAdapter.java b/java/src/com/android/intentresolver/v2/ResolverMultiProfilePagerAdapter.java index 99de3b4d..4c1358ed 100644 --- a/java/src/com/android/intentresolver/v2/ResolverMultiProfilePagerAdapter.java +++ b/java/src/com/android/intentresolver/v2/ResolverMultiProfilePagerAdapter.java @@ -27,7 +27,6 @@ import androidx.viewpager.widget.PagerAdapter; import com.android.intentresolver.R; import com.android.intentresolver.ResolverListAdapter; import com.android.intentresolver.emptystate.EmptyStateProvider; -import com.android.internal.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; @@ -43,14 +42,23 @@ public class ResolverMultiProfilePagerAdapter extends public ResolverMultiProfilePagerAdapter( Context context, - ResolverListAdapter adapter, + String personalTabLabel, + String personalTabAccessibilityLabel, + String personalTabTag, + ResolverListAdapter personalAdapter, EmptyStateProvider emptyStateProvider, Supplier<Boolean> workProfileQuietModeChecker, UserHandle workProfileUserHandle, UserHandle cloneProfileUserHandle) { this( context, - ImmutableList.of(adapter), + ImmutableList.of( + new TabConfig<>( + PROFILE_PERSONAL, + personalTabLabel, + personalTabAccessibilityLabel, + personalTabTag, + personalAdapter)), emptyStateProvider, workProfileQuietModeChecker, /* defaultProfile= */ 0, @@ -60,7 +68,13 @@ public class ResolverMultiProfilePagerAdapter extends } public ResolverMultiProfilePagerAdapter(Context context, + String personalTabLabel, + String personalTabAccessibilityLabel, + String personalTabTag, ResolverListAdapter personalAdapter, + String workTabLabel, + String workTabAccessibilityLabel, + String workTabTag, ResolverListAdapter workAdapter, EmptyStateProvider emptyStateProvider, Supplier<Boolean> workProfileQuietModeChecker, @@ -69,7 +83,19 @@ public class ResolverMultiProfilePagerAdapter extends UserHandle cloneProfileUserHandle) { this( context, - ImmutableList.of(personalAdapter, workAdapter), + ImmutableList.of( + new TabConfig<>( + PROFILE_PERSONAL, + personalTabLabel, + personalTabAccessibilityLabel, + personalTabTag, + personalAdapter), + new TabConfig<>( + PROFILE_WORK, + workTabLabel, + workTabAccessibilityLabel, + workTabTag, + workAdapter)), emptyStateProvider, workProfileQuietModeChecker, defaultProfile, @@ -80,7 +106,7 @@ public class ResolverMultiProfilePagerAdapter extends private ResolverMultiProfilePagerAdapter( Context context, - ImmutableList<ResolverListAdapter> listAdapters, + ImmutableList<TabConfig<ResolverListAdapter>> tabs, EmptyStateProvider emptyStateProvider, Supplier<Boolean> workProfileQuietModeChecker, @Profile int defaultProfile, @@ -90,7 +116,7 @@ public class ResolverMultiProfilePagerAdapter extends super( listAdapter -> listAdapter, (listView, bindAdapter) -> listView.setAdapter(bindAdapter), - listAdapters, + tabs, emptyStateProvider, workProfileQuietModeChecker, defaultProfile, |