Merge "Show empty state screens in order of priority." into rvc-dev

This commit is contained in:
Antoan Angelov
2020-03-30 19:55:11 +00:00
committed by Android (Google) Code Review
5 changed files with 208 additions and 28 deletions

View File

@@ -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()

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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,7 @@ 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();
@@ -652,6 +659,57 @@ public class ResolverActivityTest {
.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);
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();
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()));
}
private Intent createSendImageIntent() {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);