Merge "Show empty state screens in order of priority." into rvc-dev am: 9238e32a16 am: 571c0e4ea3 am: f6be54216a
Change-Id: I5a8d3b0ac07e203bce0840528a7388468fcd9c72
This commit is contained in:
@@ -300,21 +300,7 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
|
|||||||
|
|
||||||
private boolean rebuildTab(ResolverListAdapter activeListAdapter, boolean doPostProcessing) {
|
private boolean rebuildTab(ResolverListAdapter activeListAdapter, boolean doPostProcessing) {
|
||||||
UserHandle listUserHandle = activeListAdapter.getUserHandle();
|
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 (UserHandle.myUserId() != listUserHandle.getIdentifier()) {
|
||||||
if (!mInjector.hasCrossProfileIntents(activeListAdapter.getIntents(),
|
if (!mInjector.hasCrossProfileIntents(activeListAdapter.getIntents(),
|
||||||
UserHandle.myUserId(), listUserHandle.getIdentifier())) {
|
UserHandle.myUserId(), listUserHandle.getIdentifier())) {
|
||||||
@@ -352,7 +338,65 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
|
|||||||
protected abstract void showNoWorkToPersonalIntentsEmptyState(
|
protected abstract void showNoWorkToPersonalIntentsEmptyState(
|
||||||
ResolverListAdapter activeListAdapter);
|
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();
|
UserHandle listUserHandle = listAdapter.getUserHandle();
|
||||||
if (mWorkProfileUserHandle != null
|
if (mWorkProfileUserHandle != null
|
||||||
&& (UserHandle.myUserId() == listUserHandle.getIdentifier()
|
&& (UserHandle.myUserId() == listUserHandle.getIdentifier()
|
||||||
|
|||||||
@@ -994,8 +994,8 @@ public class ResolverActivity extends Activity implements
|
|||||||
if (isAutolaunching() || maybeAutolaunchActivity()) {
|
if (isAutolaunching() || maybeAutolaunchActivity()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (shouldShowEmptyState(listAdapter)) {
|
if (isResolverListEmpty(listAdapter)) {
|
||||||
mMultiProfilePagerAdapter.showNoAppsAvailableEmptyState(listAdapter);
|
mMultiProfilePagerAdapter.showEmptyResolverListEmptyState(listAdapter);
|
||||||
} else {
|
} else {
|
||||||
mMultiProfilePagerAdapter.showListView(listAdapter);
|
mMultiProfilePagerAdapter.showListView(listAdapter);
|
||||||
}
|
}
|
||||||
@@ -1640,12 +1640,12 @@ public class ResolverActivity extends Activity implements
|
|||||||
|
|
||||||
private void setupViewVisibilities() {
|
private void setupViewVisibilities() {
|
||||||
ResolverListAdapter activeListAdapter = mMultiProfilePagerAdapter.getActiveListAdapter();
|
ResolverListAdapter activeListAdapter = mMultiProfilePagerAdapter.getActiveListAdapter();
|
||||||
if (!shouldShowEmptyState(activeListAdapter)) {
|
if (!isResolverListEmpty(activeListAdapter)) {
|
||||||
addUseDifferentAppLabelIfNecessary(activeListAdapter);
|
addUseDifferentAppLabelIfNecessary(activeListAdapter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldShowEmptyState(ResolverListAdapter listAdapter) {
|
private boolean isResolverListEmpty(ResolverListAdapter listAdapter) {
|
||||||
int count = listAdapter.getUnfilteredCount();
|
int count = listAdapter.getUnfilteredCount();
|
||||||
return count == 0 && listAdapter.getPlaceholderCount() == 0;
|
return count == 0 && listAdapter.getPlaceholderCount() == 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,12 +120,32 @@ public class ResolverListController {
|
|||||||
boolean shouldGetActivityMetadata,
|
boolean shouldGetActivityMetadata,
|
||||||
List<Intent> intents,
|
List<Intent> intents,
|
||||||
UserHandle userHandle) {
|
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;
|
List<ResolverActivity.ResolvedComponentInfo> resolvedComponents = null;
|
||||||
for (int i = 0, N = intents.size(); i < N; i++) {
|
for (int i = 0, N = intents.size(); i < N; i++) {
|
||||||
final Intent intent = intents.get(i);
|
final Intent intent = intents.get(i);
|
||||||
int flags = PackageManager.MATCH_DEFAULT_ONLY
|
int flags = baseFlags;
|
||||||
| (shouldGetResolvedFilter ? PackageManager.GET_RESOLVED_FILTER : 0)
|
|
||||||
| (shouldGetActivityMetadata ? PackageManager.GET_META_DATA : 0);
|
|
||||||
if (intent.isWebIntent()
|
if (intent.isWebIntent()
|
||||||
|| (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) != 0) {
|
|| (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) != 0) {
|
||||||
flags |= PackageManager.MATCH_INSTANT;
|
flags |= PackageManager.MATCH_INSTANT;
|
||||||
|
|||||||
@@ -1330,8 +1330,15 @@ public class ChooserActivityTest {
|
|||||||
createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
|
createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
|
||||||
List<ResolvedComponentInfo> workResolvedComponentInfos =
|
List<ResolvedComponentInfo> workResolvedComponentInfos =
|
||||||
createResolvedComponentsForTest(workProfileTargets);
|
createResolvedComponentsForTest(workProfileTargets);
|
||||||
|
when(sOverrides.workResolverListController.getUserStateIndependentResolversAsUser(
|
||||||
|
Mockito.isA(List.class),
|
||||||
|
Mockito.isA(UserHandle.class)))
|
||||||
|
.thenReturn(new ArrayList<>(workResolvedComponentInfos));
|
||||||
sOverrides.isQuietModeEnabled = true;
|
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();
|
Intent sendIntent = createSendTextIntent();
|
||||||
sendIntent.setType("TestType");
|
sendIntent.setType("TestType");
|
||||||
|
|
||||||
@@ -1348,7 +1355,7 @@ public class ChooserActivityTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWorkTab_noWorkTargets_emptyStateShown() {
|
public void testWorkTab_noWorkAppsAvailable_emptyStateShown() {
|
||||||
// enable the work tab feature flag
|
// enable the work tab feature flag
|
||||||
ResolverActivity.ENABLE_TABBED_VIEW = true;
|
ResolverActivity.ENABLE_TABBED_VIEW = true;
|
||||||
markWorkProfileUserAvailable();
|
markWorkProfileUserAvailable();
|
||||||
@@ -1372,6 +1379,57 @@ public class ChooserActivityTest {
|
|||||||
.check(matches(isDisplayed()));
|
.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() {
|
private Intent createSendTextIntent() {
|
||||||
Intent sendIntent = new Intent();
|
Intent sendIntent = new Intent();
|
||||||
sendIntent.setAction(Intent.ACTION_SEND);
|
sendIntent.setAction(Intent.ACTION_SEND);
|
||||||
|
|||||||
@@ -598,7 +598,7 @@ public class ResolverActivityTest {
|
|||||||
onView(withId(R.id.contentPanel))
|
onView(withId(R.id.contentPanel))
|
||||||
.perform(swipeUp());
|
.perform(swipeUp());
|
||||||
|
|
||||||
onView(withText(R.string.resolver_cant_share_with_work_apps))
|
onView(withText(R.string.resolver_cant_access_work_apps))
|
||||||
.check(matches(isDisplayed()));
|
.check(matches(isDisplayed()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -612,8 +612,15 @@ public class ResolverActivityTest {
|
|||||||
createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
|
createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
|
||||||
List<ResolvedComponentInfo> workResolvedComponentInfos =
|
List<ResolvedComponentInfo> workResolvedComponentInfos =
|
||||||
createResolvedComponentsForTest(workProfileTargets);
|
createResolvedComponentsForTest(workProfileTargets);
|
||||||
|
when(sOverrides.workResolverListController.getUserStateIndependentResolversAsUser(
|
||||||
|
Mockito.isA(List.class),
|
||||||
|
Mockito.isA(UserHandle.class)))
|
||||||
|
.thenReturn(new ArrayList<>(workResolvedComponentInfos));
|
||||||
sOverrides.isQuietModeEnabled = true;
|
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();
|
Intent sendIntent = createSendImageIntent();
|
||||||
sendIntent.setType("TestType");
|
sendIntent.setType("TestType");
|
||||||
|
|
||||||
@@ -629,7 +636,7 @@ public class ResolverActivityTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWorkTab_noWorkTargets_emptyStateShown() {
|
public void testWorkTab_noWorkAppsAvailable_emptyStateShown() {
|
||||||
// enable the work tab feature flag
|
// enable the work tab feature flag
|
||||||
ResolverActivity.ENABLE_TABBED_VIEW = true;
|
ResolverActivity.ENABLE_TABBED_VIEW = true;
|
||||||
markWorkProfileUserAvailable();
|
markWorkProfileUserAvailable();
|
||||||
@@ -652,6 +659,57 @@ public class ResolverActivityTest {
|
|||||||
.check(matches(isDisplayed()));
|
.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() {
|
private Intent createSendImageIntent() {
|
||||||
Intent sendIntent = new Intent();
|
Intent sendIntent = new Intent();
|
||||||
sendIntent.setAction(Intent.ACTION_SEND);
|
sendIntent.setAction(Intent.ACTION_SEND);
|
||||||
|
|||||||
Reference in New Issue
Block a user