From 81e474d7a73516faa1e45a6279020471aa453232 Mon Sep 17 00:00:00 2001
From: Matt Casey
Date: Wed, 26 Jan 2022 17:13:46 -0500
Subject: [PATCH] Add 'miniresolver' UI for cross-profile single app
resolution.
When the current profile only has web browsers and the other profile has
a single non-browser app to handle the given intent, simplify the
resolver UI to present the user with a yes/no question about how to
handle.
Canonical example of this is "clicking a youtube link in your work
profile".
Bug: 175433480
Test: atest ResolverActivityTest
Change-Id: I213313ca87a8d1db5e586fe074f953060a91fc19
---
.../internal/app/ResolverActivity.java | 79 ++++++++++++-
core/res/res/layout/miniresolver.xml | 111 ++++++++++++++++++
core/res/res/values/strings.xml | 4 +-
core/res/res/values/symbols.xml | 8 ++
.../internal/app/ResolverActivityTest.java | 19 +++
5 files changed, 217 insertions(+), 4 deletions(-)
create mode 100644 core/res/res/layout/miniresolver.xml
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 347153c7e53ea..cdb69e546b8f8 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -1011,7 +1011,9 @@ public class ResolverActivity extends Activity implements
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
ViewPager viewPager = findViewById(R.id.profile_pager);
- outState.putInt(LAST_SHOWN_TAB_KEY, viewPager.getCurrentItem());
+ if (viewPager != null) {
+ outState.putInt(LAST_SHOWN_TAB_KEY, viewPager.getCurrentItem());
+ }
}
@Override
@@ -1019,7 +1021,9 @@ public class ResolverActivity extends Activity implements
super.onRestoreInstanceState(savedInstanceState);
resetButtonBar();
ViewPager viewPager = findViewById(R.id.profile_pager);
- viewPager.setCurrentItem(savedInstanceState.getInt(LAST_SHOWN_TAB_KEY));
+ if (viewPager != null) {
+ viewPager.setCurrentItem(savedInstanceState.getInt(LAST_SHOWN_TAB_KEY));
+ }
mMultiProfilePagerAdapter.clearInactiveProfileCache();
}
@@ -1568,6 +1572,11 @@ public class ResolverActivity extends Activity implements
rebuildCompleted = rebuildCompleted && rebuildInactiveCompleted;
}
+ if (shouldUseMiniResolver()) {
+ configureMiniResolverContent();
+ return false;
+ }
+
if (useLayoutWithDefault()) {
mLayoutId = R.layout.resolver_list_with_default;
} else {
@@ -1578,6 +1587,72 @@ public class ResolverActivity extends Activity implements
return postRebuildList(rebuildCompleted);
}
+ private void configureMiniResolverContent() {
+ mLayoutId = R.layout.miniresolver;
+ setContentView(mLayoutId);
+
+ DisplayResolveInfo sameProfileResolveInfo =
+ mMultiProfilePagerAdapter.getActiveListAdapter().mDisplayList.get(0);
+ boolean inWorkProfile = getCurrentProfile() == PROFILE_WORK;
+
+ DisplayResolveInfo otherProfileResolveInfo =
+ mMultiProfilePagerAdapter.getInactiveListAdapter().mDisplayList.get(0);
+ ImageView icon = findViewById(R.id.icon);
+ // TODO: Set icon drawable to app icon.
+
+ ((TextView) findViewById(R.id.open_cross_profile)).setText(
+ getResources().getString(
+ inWorkProfile ? R.string.miniresolver_open_in_personal
+ : R.string.miniresolver_open_in_work,
+ otherProfileResolveInfo.getDisplayLabel()));
+ ((Button) findViewById(R.id.use_same_profile_browser)).setText(
+ inWorkProfile ? R.string.miniresolver_use_work_browser
+ : R.string.miniresolver_use_personal_browser);
+
+ findViewById(R.id.use_same_profile_browser).setOnClickListener(
+ v -> safelyStartActivity(sameProfileResolveInfo));
+
+ findViewById(R.id.button_open).setOnClickListener(v -> {
+ Intent intent = otherProfileResolveInfo.getResolvedIntent();
+ if (intent != null) {
+ prepareIntentForCrossProfileLaunch(intent);
+ }
+ safelyStartActivityInternal(otherProfileResolveInfo,
+ mMultiProfilePagerAdapter.getInactiveListAdapter().mResolverListController
+ .getUserHandle());
+ });
+ }
+
+ private boolean shouldUseMiniResolver() {
+ if (mMultiProfilePagerAdapter.getActiveListAdapter() == null
+ || mMultiProfilePagerAdapter.getInactiveListAdapter() == null) {
+ return false;
+ }
+ List sameProfileList =
+ mMultiProfilePagerAdapter.getActiveListAdapter().mDisplayList;
+ List otherProfileList =
+ mMultiProfilePagerAdapter.getInactiveListAdapter().mDisplayList;
+
+ if (otherProfileList.size() != 1) {
+ Log.d(TAG, "Found " + otherProfileList.size() + " resolvers in the other profile");
+ return false;
+ }
+
+ if (otherProfileList.get(0).getResolveInfo().handleAllWebDataURI) {
+ Log.d(TAG, "Other profile is a web browser");
+ return false;
+ }
+
+ for (DisplayResolveInfo info : sameProfileList) {
+ if (!info.getResolveInfo().handleAllWebDataURI) {
+ Log.d(TAG, "Non-browser found in this profile");
+ return false;
+ }
+ }
+
+ return true;
+ }
+
/**
* Finishing procedures to be performed after the list has been rebuilt.
*
Subclasses must call postRebuildListInternal at the end of postRebuildList.
diff --git a/core/res/res/layout/miniresolver.xml b/core/res/res/layout/miniresolver.xml
new file mode 100644
index 0000000000000..44ed6f2a06765
--- /dev/null
+++ b/core/res/res/layout/miniresolver.xml
@@ -0,0 +1,111 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 49a12d12ed212..9a215c448c27b 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5949,9 +5949,9 @@
No personal apps
- Open in %s in personal profile?
+ Open %s in your personal profile?
- Open in %s in work profile?
+ Open %s in your work profile?
Use personal browser
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 85eed85a9e70f..ec374ae74dcbb 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1597,6 +1597,13 @@
+
+
+
+
+
+
+
@@ -2705,6 +2712,7 @@
+
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
index 75d20252ae274..2817728fd9eab 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
@@ -730,6 +730,25 @@ public class ResolverActivityTest {
.check(matches(isDisplayed()));
}
+ @Test
+ public void testMiniResolver() {
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ markWorkProfileUserAvailable();
+ List personalResolvedComponentInfos =
+ createResolvedComponentsForTest(1);
+ List workResolvedComponentInfos =
+ createResolvedComponentsForTest(1);
+ // Personal profile only has a browser
+ personalResolvedComponentInfos.get(0).getResolveInfoAt(0).handleAllWebDataURI = true;
+ setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
+ Intent sendIntent = createSendImageIntent();
+ sendIntent.setType("TestType");
+
+ mActivityRule.launchActivity(sendIntent);
+ waitForIdle();
+ onView(withId(R.id.open_cross_profile)).check(matches(isDisplayed()));
+ }
+
@Test
public void testWorkTab_noAppsAvailable_workOff_noAppsAvailableEmptyStateShown() {
// enable the work tab feature flag