summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java76
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java8
-rw-r--r--core/java/com/android/internal/app/ResolverListController.java26
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java62
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java64
5 files changed, 208 insertions, 28 deletions
diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
index c53516389cd9..9fc0da83c504 100644
--- a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
@@ -300,21 +300,7 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
private boolean rebuildTab(ResolverListAdapter activeListAdapter, boolean doPostProcessing) {
UserHandle listUserHandle = activeListAdapter.getUserHandle();
- if (listUserHandle.equals(mWorkProfileUserHandle)
- && mInjector.isQuietModeEnabled(mWorkProfileUserHandle)) {
- DevicePolicyEventLogger
- .createEvent(DevicePolicyEnums.RESOLVER_EMPTY_STATE_WORK_APPS_DISABLED)
- .setStrings(getMetricsCategory())
- .write();
- showWorkProfileOffEmptyState(activeListAdapter,
- v -> {
- ProfileDescriptor descriptor = getItem(
- userHandleToPageIndex(activeListAdapter.getUserHandle()));
- showSpinner(descriptor.getEmptyStateView());
- mInjector.requestQuietModeEnabled(false, mWorkProfileUserHandle);
- });
- return false;
- }
+
if (UserHandle.myUserId() != listUserHandle.getIdentifier()) {
if (!mInjector.hasCrossProfileIntents(activeListAdapter.getIntents(),
UserHandle.myUserId(), listUserHandle.getIdentifier())) {
@@ -352,7 +338,65 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
protected abstract void showNoWorkToPersonalIntentsEmptyState(
ResolverListAdapter activeListAdapter);
- void showNoAppsAvailableEmptyState(ResolverListAdapter listAdapter) {
+ /**
+ * The empty state screens are shown according to their priority:
+ * <ol>
+ * <li>(highest priority) cross-profile disabled by policy (handled in
+ * {@link #rebuildTab(ResolverListAdapter, boolean)})</li>
+ * <li>no apps available</li>
+ * <li>(least priority) work is off</li>
+ * </ol>
+ *
+ * The intention is to prevent the user from having to turn
+ * the work profile on if there will not be any apps resolved
+ * anyway.
+ */
+ void showEmptyResolverListEmptyState(ResolverListAdapter listAdapter) {
+ if (maybeShowWorkProfileOffEmptyState(listAdapter)) {
+ return;
+ }
+ maybeShowNoAppsAvailableEmptyState(listAdapter);
+ }
+
+ /**
+ * Returns {@code true} if the work profile off empty state screen is shown.
+ */
+ private boolean maybeShowWorkProfileOffEmptyState(ResolverListAdapter listAdapter) {
+ UserHandle listUserHandle = listAdapter.getUserHandle();
+ if (!listUserHandle.equals(mWorkProfileUserHandle)
+ || !mInjector.isQuietModeEnabled(mWorkProfileUserHandle)
+ || !hasResolvedAppsInWorkProfile(listAdapter)) {
+ return false;
+ }
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.RESOLVER_EMPTY_STATE_WORK_APPS_DISABLED)
+ .setStrings(getMetricsCategory())
+ .write();
+ showWorkProfileOffEmptyState(listAdapter,
+ v -> {
+ ProfileDescriptor descriptor = getItem(
+ userHandleToPageIndex(listAdapter.getUserHandle()));
+ showSpinner(descriptor.getEmptyStateView());
+ mInjector.requestQuietModeEnabled(false, mWorkProfileUserHandle);
+ });
+ return true;
+ }
+
+ /**
+ * Returns {@code true} if there is at least one app resolved in the work profile,
+ * regardless of whether the work profile is enabled or not.
+ */
+ private boolean hasResolvedAppsInWorkProfile(ResolverListAdapter listAdapter) {
+ List<ResolverActivity.ResolvedComponentInfo> userStateIndependentWorkResolvers =
+ listAdapter.mResolverListController.getUserStateIndependentResolversAsUser(
+ listAdapter.getIntents(), mWorkProfileUserHandle);
+ return userStateIndependentWorkResolvers.stream()
+ .anyMatch(resolvedComponentInfo ->
+ resolvedComponentInfo.getResolveInfoAt(0).targetUserId
+ == UserHandle.USER_CURRENT);
+ }
+
+ private void maybeShowNoAppsAvailableEmptyState(ResolverListAdapter listAdapter) {
UserHandle listUserHandle = listAdapter.getUserHandle();
if (mWorkProfileUserHandle != null
&& (UserHandle.myUserId() == listUserHandle.getIdentifier()
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 2352180bcba3..f088ab38658c 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -994,8 +994,8 @@ public class ResolverActivity extends Activity implements
if (isAutolaunching() || maybeAutolaunchActivity()) {
return;
}
- if (shouldShowEmptyState(listAdapter)) {
- mMultiProfilePagerAdapter.showNoAppsAvailableEmptyState(listAdapter);
+ if (isResolverListEmpty(listAdapter)) {
+ mMultiProfilePagerAdapter.showEmptyResolverListEmptyState(listAdapter);
} else {
mMultiProfilePagerAdapter.showListView(listAdapter);
}
@@ -1640,12 +1640,12 @@ public class ResolverActivity extends Activity implements
private void setupViewVisibilities() {
ResolverListAdapter activeListAdapter = mMultiProfilePagerAdapter.getActiveListAdapter();
- if (!shouldShowEmptyState(activeListAdapter)) {
+ if (!isResolverListEmpty(activeListAdapter)) {
addUseDifferentAppLabelIfNecessary(activeListAdapter);
}
}
- private boolean shouldShowEmptyState(ResolverListAdapter listAdapter) {
+ private boolean isResolverListEmpty(ResolverListAdapter listAdapter) {
int count = listAdapter.getUnfilteredCount();
return count == 0 && listAdapter.getPlaceholderCount() == 0;
}
diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java
index 51dce5547890..3f897a5f26bf 100644
--- a/core/java/com/android/internal/app/ResolverListController.java
+++ b/core/java/com/android/internal/app/ResolverListController.java
@@ -120,12 +120,32 @@ public class ResolverListController {
boolean shouldGetActivityMetadata,
List<Intent> intents,
UserHandle userHandle) {
+ int baseFlags = PackageManager.MATCH_DEFAULT_ONLY
+ | (shouldGetResolvedFilter ? PackageManager.GET_RESOLVED_FILTER : 0)
+ | (shouldGetActivityMetadata ? PackageManager.GET_META_DATA : 0);
+ return getResolversForIntentAsUserInternal(intents, userHandle, baseFlags);
+ }
+
+ /**
+ * Returns a list of resolved intents which is user state-independent. This means it will
+ * return the same results regardless of whether the {@code userHandle} user is disabled or not.
+ */
+ public List<ResolverActivity.ResolvedComponentInfo> getUserStateIndependentResolversAsUser(
+ List<Intent> intents,
+ UserHandle userHandle) {
+ int baseFlags = PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+ return getResolversForIntentAsUserInternal(intents, userHandle, baseFlags);
+ }
+
+ private List<ResolverActivity.ResolvedComponentInfo> getResolversForIntentAsUserInternal(
+ List<Intent> intents,
+ UserHandle userHandle,
+ int baseFlags) {
List<ResolverActivity.ResolvedComponentInfo> resolvedComponents = null;
for (int i = 0, N = intents.size(); i < N; i++) {
final Intent intent = intents.get(i);
- int flags = PackageManager.MATCH_DEFAULT_ONLY
- | (shouldGetResolvedFilter ? PackageManager.GET_RESOLVED_FILTER : 0)
- | (shouldGetActivityMetadata ? PackageManager.GET_META_DATA : 0);
+ int flags = baseFlags;
if (intent.isWebIntent()
|| (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) != 0) {
flags |= PackageManager.MATCH_INSTANT;
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index e427421a5a80..812e2a6c63fd 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -1330,8 +1330,15 @@ public class ChooserActivityTest {
createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
List<ResolvedComponentInfo> workResolvedComponentInfos =
createResolvedComponentsForTest(workProfileTargets);
+ when(sOverrides.workResolverListController.getUserStateIndependentResolversAsUser(
+ Mockito.isA(List.class),
+ Mockito.isA(UserHandle.class)))
+ .thenReturn(new ArrayList<>(workResolvedComponentInfos));
sOverrides.isQuietModeEnabled = true;
- setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
+ // When work profile is disabled, we get 0 results when we query the work profile
+ // intents.
+ setupResolverControllers(personalResolvedComponentInfos,
+ /* workResolvedComponentInfos */ new ArrayList<>());
Intent sendIntent = createSendTextIntent();
sendIntent.setType("TestType");
@@ -1348,7 +1355,7 @@ public class ChooserActivityTest {
}
@Test
- public void testWorkTab_noWorkTargets_emptyStateShown() {
+ public void testWorkTab_noWorkAppsAvailable_emptyStateShown() {
// enable the work tab feature flag
ResolverActivity.ENABLE_TABBED_VIEW = true;
markWorkProfileUserAvailable();
@@ -1372,6 +1379,57 @@ public class ChooserActivityTest {
.check(matches(isDisplayed()));
}
+ @Test
+ public void testWorkTab_xProfileOff_noAppsAvailable_workOff_xProfileOffEmptyStateShown() {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ markWorkProfileUserAvailable();
+ List<ResolvedComponentInfo> personalResolvedComponentInfos =
+ createResolvedComponentsForTest(3);
+ List<ResolvedComponentInfo> workResolvedComponentInfos =
+ createResolvedComponentsForTest(0);
+ setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
+ sOverrides.isQuietModeEnabled = true;
+ sOverrides.hasCrossProfileIntents = false;
+ Intent sendIntent = createSendTextIntent();
+ sendIntent.setType("TestType");
+
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
+ waitForIdle();
+ onView(withId(R.id.contentPanel))
+ .perform(swipeUp());
+ onView(withText(R.string.resolver_work_tab)).perform(click());
+ waitForIdle();
+
+ onView(withText(R.string.resolver_cant_share_with_work_apps))
+ .check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void testWorkTab_noAppsAvailable_workOff_noAppsAvailableEmptyStateShown() {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ markWorkProfileUserAvailable();
+ List<ResolvedComponentInfo> personalResolvedComponentInfos =
+ createResolvedComponentsForTest(3);
+ List<ResolvedComponentInfo> workResolvedComponentInfos =
+ createResolvedComponentsForTest(0);
+ setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
+ sOverrides.isQuietModeEnabled = true;
+ Intent sendIntent = createSendTextIntent();
+ sendIntent.setType("TestType");
+
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
+ waitForIdle();
+ onView(withId(R.id.contentPanel))
+ .perform(swipeUp());
+ onView(withText(R.string.resolver_work_tab)).perform(click());
+ waitForIdle();
+
+ onView(withText(R.string.resolver_no_work_apps_available_share))
+ .check(matches(isDisplayed()));
+ }
+
private Intent createSendTextIntent() {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
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 4ec89b7d2817..5a3aff937b79 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
@@ -598,7 +598,7 @@ public class ResolverActivityTest {
onView(withId(R.id.contentPanel))
.perform(swipeUp());
- onView(withText(R.string.resolver_cant_share_with_work_apps))
+ onView(withText(R.string.resolver_cant_access_work_apps))
.check(matches(isDisplayed()));
}
@@ -612,8 +612,15 @@ public class ResolverActivityTest {
createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
List<ResolvedComponentInfo> workResolvedComponentInfos =
createResolvedComponentsForTest(workProfileTargets);
+ when(sOverrides.workResolverListController.getUserStateIndependentResolversAsUser(
+ Mockito.isA(List.class),
+ Mockito.isA(UserHandle.class)))
+ .thenReturn(new ArrayList<>(workResolvedComponentInfos));
sOverrides.isQuietModeEnabled = true;
- setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
+ // When work profile is disabled, we get 0 results when we query the work profile
+ // intents.
+ setupResolverControllers(personalResolvedComponentInfos,
+ /* workResolvedComponentInfos */ new ArrayList<>());
Intent sendIntent = createSendImageIntent();
sendIntent.setType("TestType");
@@ -629,7 +636,31 @@ public class ResolverActivityTest {
}
@Test
- public void testWorkTab_noWorkTargets_emptyStateShown() {
+ public void testWorkTab_noWorkAppsAvailable_emptyStateShown() {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ markWorkProfileUserAvailable();
+ List<ResolvedComponentInfo> personalResolvedComponentInfos =
+ createResolvedComponentsForTest(3);
+ List<ResolvedComponentInfo> workResolvedComponentInfos =
+ createResolvedComponentsForTest(0);
+ setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
+ Intent sendIntent = createSendImageIntent();
+ sendIntent.setType("TestType");
+
+ mActivityRule.launchActivity(sendIntent);
+ waitForIdle();
+ onView(withId(R.id.contentPanel))
+ .perform(swipeUp());
+ onView(withText(R.string.resolver_work_tab)).perform(click());
+ waitForIdle();
+
+ onView(withText(R.string.resolver_no_work_apps_available_resolve))
+ .check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void testWorkTab_xProfileOff_noAppsAvailable_workOff_xProfileOffEmptyStateShown() {
// enable the work tab feature flag
ResolverActivity.ENABLE_TABBED_VIEW = true;
markWorkProfileUserAvailable();
@@ -640,6 +671,33 @@ public class ResolverActivityTest {
setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
Intent sendIntent = createSendImageIntent();
sendIntent.setType("TestType");
+ sOverrides.isQuietModeEnabled = true;
+ sOverrides.hasCrossProfileIntents = false;
+
+ mActivityRule.launchActivity(sendIntent);
+ waitForIdle();
+ onView(withId(R.id.contentPanel))
+ .perform(swipeUp());
+ onView(withText(R.string.resolver_work_tab)).perform(click());
+ waitForIdle();
+
+ onView(withText(R.string.resolver_cant_access_work_apps))
+ .check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void testWorkTab_noAppsAvailable_workOff_noAppsAvailableEmptyStateShown() {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ markWorkProfileUserAvailable();
+ List<ResolvedComponentInfo> personalResolvedComponentInfos =
+ createResolvedComponentsForTest(3);
+ List<ResolvedComponentInfo> workResolvedComponentInfos =
+ createResolvedComponentsForTest(0);
+ setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
+ Intent sendIntent = createSendImageIntent();
+ sendIntent.setType("TestType");
+ sOverrides.isQuietModeEnabled = true;
mActivityRule.launchActivity(sendIntent);
waitForIdle();