summaryrefslogtreecommitdiff
path: root/java/src
diff options
context:
space:
mode:
author Joshua Trask <joshtrask@google.com> 2023-12-15 16:00:56 +0000
committer Joshua Trask <joshtrask@google.com> 2023-12-18 19:14:58 +0000
commitf07f2e8c571915cf69e3367805eda273cb1bc4d0 (patch)
tree91fb37ccbb5a1b57851e36e46bbc617f4ed9b103 /java/src
parent37b363161b23f4b9d4c85713468c38613fc5fbc4 (diff)
More "favoring to identify tabs by profile"
Switching over more cases in the style of ag/25661285. These changes are as prototyped in ag/25335069 and described in go/chooser-ntab-refactoring, in particular replicating the changes of "snapshot 26" through "snapshot 30." See below for a "by-snapshot" breakdown of the incremental changes composed in this CL. Snapshot 1: Change the signature of the pager's listener API to include both profile ID and page number, and update the (one) implementation to be explicit about which mechanism it's trying to use. Snapshot 2: Add metadata to the pager's `ProfileDescriptor` to identify the associated profile, and begin to generalize away from the assumption that profile ID numbers are equivalent to their associated page numbers (i.e., their indexes in the `mItems` list). Snapshot 3: Move ResolverActivity's `updateActiveTabStyle()` to be an internal implementation detail (as a "lambda") of its `setupProfileTabs()` method. An upcoming snapshot will move `setupProfileTabs()` to the pager, and this prepares to move it as a unit. Snapshot 4: Move "application" logic for tab-switches into the existing `onProfileTabSelected()` callback, again to make `setupProfileTabs()` more generic in preparation to move it over to the pager. Snapshot 5 rebase / snapshot 6 fix conflicts (notably, `ChooserActivity` no longer inherits from `ResolverActivity` and so the changes to `ResolverActivity` needed to be replicated in Chooser.) (Remaining snapshots are tweaks to continue fixing merge conflicts.) Bug: 310211468 Test: `IntentResolver-tests-actvity`, `ResolverActivityTest` Change-Id: I9a51a671447a6c4d1a200bf3b0a12a33088ac042
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/intentresolver/v2/ChooserActivity.java48
-rw-r--r--java/src/com/android/intentresolver/v2/MultiProfilePagerAdapter.java57
-rw-r--r--java/src/com/android/intentresolver/v2/ResolverActivity.java58
3 files changed, 112 insertions, 51 deletions
diff --git a/java/src/com/android/intentresolver/v2/ChooserActivity.java b/java/src/com/android/intentresolver/v2/ChooserActivity.java
index 2d2c71af..f94ed247 100644
--- a/java/src/com/android/intentresolver/v2/ChooserActivity.java
+++ b/java/src/com/android/intentresolver/v2/ChooserActivity.java
@@ -140,6 +140,7 @@ import com.android.intentresolver.model.AppPredictionServiceResolverComparator;
import com.android.intentresolver.model.ResolverRankerServiceResolverComparator;
import com.android.intentresolver.shortcuts.AppPredictorFactory;
import com.android.intentresolver.shortcuts.ShortcutLoader;
+import com.android.intentresolver.v2.MultiProfilePagerAdapter.Profile;
import com.android.intentresolver.v2.data.repository.DevicePolicyResources;
import com.android.intentresolver.v2.emptystate.NoAppsAvailableEmptyStateProvider;
import com.android.intentresolver.v2.emptystate.NoCrossProfileEmptyStateProvider;
@@ -1161,14 +1162,6 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
return false;
}
- private void updateActiveTabStyle(TabHost tabHost) {
- int currentTab = tabHost.getCurrentTab();
- TextView selected = (TextView) tabHost.getTabWidget().getChildAt(currentTab);
- TextView unselected = (TextView) tabHost.getTabWidget().getChildAt(1 - currentTab);
- selected.setSelected(true);
- unselected.setSelected(false);
- }
-
private void setupProfileTabs() {
TabHost tabHost = findViewById(com.android.internal.R.id.profile_tabhost);
tabHost.setup();
@@ -1198,23 +1191,25 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
TabWidget tabWidget = tabHost.getTabWidget();
tabWidget.setVisibility(View.VISIBLE);
- updateActiveTabStyle(tabHost);
+
+ Runnable updateActiveTabStyle = () -> {
+ int currentTab = tabHost.getCurrentTab();
+ TextView selected = (TextView) tabHost.getTabWidget().getChildAt(currentTab);
+ TextView unselected = (TextView) tabHost.getTabWidget().getChildAt(1 - currentTab);
+ selected.setSelected(true);
+ unselected.setSelected(false);
+ };
+
+ updateActiveTabStyle.run();
tabHost.setOnTabChangedListener(tabId -> {
- updateActiveTabStyle(tabHost);
+ updateActiveTabStyle.run();
if (TAB_TAG_PERSONAL.equals(tabId)) {
viewPager.setCurrentItem(0);
} else {
viewPager.setCurrentItem(1);
}
- setupViewVisibilities();
- maybeLogProfileChange();
- onProfileTabSelected();
- DevicePolicyEventLogger
- .createEvent(DevicePolicyEnums.RESOLVER_SWITCH_TABS)
- .setInt(viewPager.getCurrentItem())
- .setStrings(getMetricsCategory())
- .write();
+ onProfileTabSelected(viewPager.getCurrentItem());
});
viewPager.setVisibility(View.VISIBLE);
@@ -1222,8 +1217,8 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
mChooserMultiProfilePagerAdapter.setOnProfileSelectedListener(
new MultiProfilePagerAdapter.OnProfileSelectedListener() {
@Override
- public void onProfileSelected(int index) {
- tabHost.setCurrentTab(index);
+ public void onProfilePageSelected(@Profile int profileId, int pageNumber) {
+ tabHost.setCurrentTab(pageNumber);
}
@@ -2618,7 +2613,18 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
return METRICS_CATEGORY_CHOOSER;
}
- protected void onProfileTabSelected() {
+ protected void onProfileTabSelected(int currentPage) {
+ setupViewVisibilities();
+ maybeLogProfileChange();
+ if (hasWorkProfile()) {
+ // The device policy logger is only concerned with sessions that include a work profile.
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.RESOLVER_SWITCH_TABS)
+ .setInt(currentPage)
+ .setStrings(getMetricsCategory())
+ .write();
+ }
+
// This fixes an edge case where after performing a variety of gestures, vertical scrolling
// ends up disabled. That's because at some point the old tab's vertical scrolling is
// disabled and the new tab's is enabled. For context, see b/159997845
diff --git a/java/src/com/android/intentresolver/v2/MultiProfilePagerAdapter.java b/java/src/com/android/intentresolver/v2/MultiProfilePagerAdapter.java
index c8e9481a..dc821e88 100644
--- a/java/src/com/android/intentresolver/v2/MultiProfilePagerAdapter.java
+++ b/java/src/com/android/intentresolver/v2/MultiProfilePagerAdapter.java
@@ -129,25 +129,54 @@ class MultiProfilePagerAdapter<
ImmutableList.Builder<ProfileDescriptor<PageViewT, SinglePageAdapterT>> items =
new ImmutableList.Builder<>();
- for (SinglePageAdapterT adapter : adapters) {
- items.add(createProfileDescriptor(adapter, containerBottomPaddingOverrideSupplier));
+ // 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));
+ }
}
mItems = items.build();
}
private ProfileDescriptor<PageViewT, SinglePageAdapterT> createProfileDescriptor(
+ @Profile int profile,
SinglePageAdapterT adapter,
Supplier<Optional<Integer>> containerBottomPaddingOverrideSupplier) {
return new ProfileDescriptor<>(
- mPageViewInflater.get(), adapter, containerBottomPaddingOverrideSupplier);
+ profile, mPageViewInflater.get(), adapter, containerBottomPaddingOverrideSupplier);
}
private @Profile int getProfileForPageNumber(int position) {
- return position;
+ if (hasAdapterForIndex(position)) {
+ return mItems.get(position).mProfile;
+ }
+ return -1;
}
private int getPageNumberForProfile(@Profile int profile) {
- return profile;
+ for (int i = 0; i < mItems.size(); ++i) {
+ if (profile == mItems.get(i).mProfile) {
+ return i;
+ }
+ }
+ return -1;
}
public void setOnProfileSelectedListener(OnProfileSelectedListener listener) {
@@ -169,7 +198,8 @@ class MultiProfilePagerAdapter<
mLoadedPages.add(position);
}
if (mOnProfileSelectedListener != null) {
- mOnProfileSelectedListener.onProfileSelected(position);
+ mOnProfileSelectedListener.onProfilePageSelected(
+ getProfileForPageNumber(position), position);
}
}
@@ -599,6 +629,8 @@ class MultiProfilePagerAdapter<
// TODO: `ChooserActivity` also has a per-profile record type. Maybe the "multi-profile pager"
// 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 ViewGroup mRootView;
final EmptyStateUiHelper mEmptyStateUi;
@@ -610,9 +642,11 @@ class MultiProfilePagerAdapter<
private final PageViewT mView;
ProfileDescriptor(
+ @Profile int forProfile,
ViewGroup rootView,
SinglePageAdapterT adapter,
Supplier<Optional<Integer>> containerBottomPaddingOverrideSupplier) {
+ mProfile = forProfile;
mRootView = rootView;
mAdapter = adapter;
mEmptyStateView = rootView.findViewById(com.android.internal.R.id.resolver_empty_state);
@@ -635,13 +669,14 @@ class MultiProfilePagerAdapter<
/** Listener interface for changes between the per-profile UI tabs. */
public interface OnProfileSelectedListener {
/**
- * Callback for when the user changes the active tab from personal to work or vice versa.
+ * Callback for when the user changes the active tab.
* <p>This callback is only called when the intent resolver or share sheet shows
- * the work and personal profiles.
- * @param profileIndex {@link #PROFILE_PERSONAL} if the personal profile was selected or
- * {@link #PROFILE_WORK} if the work profile was selected.
+ * more than one profile.
+ * @param profileId the ID of the newly-selected profile, e.g. {@link #PROFILE_PERSONAL}
+ * if the personal profile tab was selected or {@link #PROFILE_WORK} if the work profile tab
+ * was selected.
*/
- void onProfileSelected(int profileIndex);
+ void onProfilePageSelected(@Profile int profileId, int pageNumber);
/**
diff --git a/java/src/com/android/intentresolver/v2/ResolverActivity.java b/java/src/com/android/intentresolver/v2/ResolverActivity.java
index a56d15a2..bc3fb16b 100644
--- a/java/src/com/android/intentresolver/v2/ResolverActivity.java
+++ b/java/src/com/android/intentresolver/v2/ResolverActivity.java
@@ -774,6 +774,31 @@ public class ResolverActivity extends Hilt_ResolverActivity implements
}
/**
+ * Callback called when user changes the profile tab.
+ */
+ /* TODO: consider merging with the customized considerations of our implemented
+ * {@link MultiProfilePagerAdapter.OnProfileSelectedListener}. The only apparent distinctions
+ * between the respective listener callbacks would occur in the triggering patterns during init
+ * (when the `OnProfileSelectedListener` is registered after a possible tab-change), or possibly
+ * if there's some way to trigger an update in one model but not the other. If there's an
+ * initialization dependency, we can probably reason about it with confidence. If there's a
+ * discrepancy between the `TabHost` and pager-adapter data models, that inconsistency is
+ * likely to be a bug that would benefit from consolidation.
+ */
+ protected void onProfileTabSelected(int currentPage) {
+ setupViewVisibilities();
+ maybeLogProfileChange();
+ if (hasWorkProfile()) {
+ // The device policy logger is only concerned with sessions that include a work profile.
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.RESOLVER_SWITCH_TABS)
+ .setInt(currentPage)
+ .setStrings(getMetricsCategory())
+ .write();
+ }
+ }
+
+ /**
* Add a label to signify that the user can pick a different app.
* @param adapter The adapter used to provide data to item views.
*/
@@ -1717,14 +1742,6 @@ public class ResolverActivity extends Hilt_ResolverActivity implements
.clearCheckedItemsInInactiveProfiles();
}
- private void updateActiveTabStyle(TabHost tabHost) {
- int currentTab = tabHost.getCurrentTab();
- TextView selected = (TextView) tabHost.getTabWidget().getChildAt(currentTab);
- TextView unselected = (TextView) tabHost.getTabWidget().getChildAt(1 - currentTab);
- selected.setSelected(true);
- unselected.setSelected(false);
- }
-
private void setupViewVisibilities() {
ResolverListAdapter activeListAdapter = mMultiProfilePagerAdapter.getActiveListAdapter();
if (!mMultiProfilePagerAdapter.shouldShowEmptyStateScreen(activeListAdapter)) {
@@ -1906,22 +1923,25 @@ public class ResolverActivity extends Hilt_ResolverActivity implements
TabWidget tabWidget = tabHost.getTabWidget();
tabWidget.setVisibility(View.VISIBLE);
- updateActiveTabStyle(tabHost);
+
+ Runnable updateActiveTabStyle = () -> {
+ int currentTab = tabHost.getCurrentTab();
+ TextView selected = (TextView) tabHost.getTabWidget().getChildAt(currentTab);
+ TextView unselected = (TextView) tabHost.getTabWidget().getChildAt(1 - currentTab);
+ selected.setSelected(true);
+ unselected.setSelected(false);
+ };
+
+ updateActiveTabStyle.run();
tabHost.setOnTabChangedListener(tabId -> {
- updateActiveTabStyle(tabHost);
+ updateActiveTabStyle.run();
if (TAB_TAG_PERSONAL.equals(tabId)) {
viewPager.setCurrentItem(0);
} else {
viewPager.setCurrentItem(1);
}
- setupViewVisibilities();
- maybeLogProfileChange();
- DevicePolicyEventLogger
- .createEvent(DevicePolicyEnums.RESOLVER_SWITCH_TABS)
- .setInt(viewPager.getCurrentItem())
- .setStrings(getMetricsCategory())
- .write();
+ onProfileTabSelected(viewPager.getCurrentItem());
});
viewPager.setVisibility(View.VISIBLE);
@@ -1929,8 +1949,8 @@ public class ResolverActivity extends Hilt_ResolverActivity implements
mMultiProfilePagerAdapter.setOnProfileSelectedListener(
new MultiProfilePagerAdapter.OnProfileSelectedListener() {
@Override
- public void onProfileSelected(int index) {
- tabHost.setCurrentTab(index);
+ public void onProfilePageSelected(@Profile int profileId, int pageNumber) {
+ tabHost.setCurrentTab(pageNumber);
resetButtonBar();
resetCheckedItem();
}