Start sharesheet in the same profile instead of switching to other profile.

Instead of starting the sharesheet in the other profile when
choosing the "Switch to work"/"Switch to personal" button,
we now start the sharesheet in the same profile with the other tab
selected.

For example, we're in the personal profile and share something
via an app that uses its own sharing logic. That shows the
"Switch to work" button and when we press it, we now start
the sharesheet in the personal profile with the work tab selected.

The reason for this is to avoid user confusion when they go back
to the personal tab and it shows an empty state screen due to
lack of cross-profile intents.

Fixes: 152866292
Test: manual
Test: atest ChooserActivityTest
Test: atest ResolverActivityTest
Test: atest IntentForwarderActivityTest#launchInSameProfile_chooserIntent
Change-Id: Ic117c9c51c663b6574e7692022bac82f7c899ec2
This commit is contained in:
arangelov
2020-04-07 17:10:36 +01:00
parent 7eb72faa06
commit c758139095
3 changed files with 86 additions and 22 deletions

View File

@@ -169,6 +169,17 @@ public class ChooserActivity extends ResolverActivity implements
public static final String EXTRA_PRIVATE_RETAIN_IN_ON_STOP
= "com.android.internal.app.ChooserActivity.EXTRA_PRIVATE_RETAIN_IN_ON_STOP";
/**
* Integer extra to indicate which profile should be automatically selected.
* <p>Can only be used if there is a work profile.
* <p>Possible values can be either {@link #PROFILE_PERSONAL} or {@link #PROFILE_WORK}.
*/
static final String EXTRA_SELECTED_PROFILE =
"com.android.internal.app.ChooserActivity.EXTRA_SELECTED_PROFILE";
static final int PROFILE_PERSONAL = AbstractMultiProfilePagerAdapter.PROFILE_PERSONAL;
static final int PROFILE_WORK = AbstractMultiProfilePagerAdapter.PROFILE_WORK;
private static final String PREF_NUM_SHEET_EXPANSIONS = "pref_num_sheet_expansions";
private static final String CHIP_LABEL_METADATA_KEY = "android.service.chooser.chip_label";
@@ -860,15 +871,31 @@ public class ChooserActivity extends ResolverActivity implements
filterLastUsed,
mUseLayoutForBrowsables,
/* userHandle */ getWorkProfileUserHandle());
int selectedProfile = findSelectedProfile();
return new ChooserMultiProfilePagerAdapter(
/* context */ this,
personalAdapter,
workAdapter,
/* defaultProfile */ getCurrentProfile(),
selectedProfile,
getPersonalProfileUserHandle(),
getWorkProfileUserHandle());
}
private int findSelectedProfile() {
int selectedProfile;
if (getIntent().hasExtra(EXTRA_SELECTED_PROFILE)) {
selectedProfile = getIntent().getIntExtra(EXTRA_SELECTED_PROFILE, /* defValue = */ -1);
if (selectedProfile != PROFILE_PERSONAL && selectedProfile != PROFILE_WORK) {
throw new IllegalArgumentException(EXTRA_SELECTED_PROFILE + " has invalid value "
+ selectedProfile + ". Must be either ChooserActivity.PROFILE_PERSONAL or "
+ "ChooserActivity.PROFILE_WORK.");
}
} else {
selectedProfile = getProfileForUser(getUser());
}
return selectedProfile;
}
@Override
protected boolean postRebuildList(boolean rebuildCompleted) {
updateStickyContentPreview();
@@ -2479,7 +2506,10 @@ public class ChooserActivity extends ResolverActivity implements
gridAdapter.getMaxTargetsPerRow());
}
if (mChooserMultiProfilePagerAdapter.getCurrentUserHandle() != getUser()) {
UserHandle currentUserHandle = mChooserMultiProfilePagerAdapter.getCurrentUserHandle();
int currentProfile = getProfileForUser(currentUserHandle);
int initialProfile = findSelectedProfile();
if (currentProfile != initialProfile) {
return;
}
@@ -2576,6 +2606,19 @@ public class ChooserActivity extends ResolverActivity implements
}
}
/**
* Returns {@link #PROFILE_PERSONAL}, {@link #PROFILE_WORK}, or -1 if the given user handle
* does not match either the personal or work user handle.
**/
private int getProfileForUser(UserHandle currentUserHandle) {
if (currentUserHandle == getPersonalProfileUserHandle()) {
return PROFILE_PERSONAL;
} else if (currentUserHandle == getWorkProfileUserHandle()) {
return PROFILE_WORK;
}
return -1;
}
private ViewGroup getCurrentEmptyStateView() {
int currentPage = mChooserMultiProfilePagerAdapter.getCurrentPage();
return mChooserMultiProfilePagerAdapter.getItem(currentPage).getEmptyStateView();

View File

@@ -108,20 +108,16 @@ public class IntentForwarderActivity extends Activity {
finish();
return;
}
if (Intent.ACTION_CHOOSER.equals(intentReceived.getAction())) {
launchChooserActivityWithCorrectTab(intentReceived, className);
return;
}
final int callingUserId = getUserId();
final Intent newIntent = canForward(intentReceived, getUserId(), targetUserId,
mInjector.getIPackageManager(), getContentResolver());
if (newIntent != null) {
if (Intent.ACTION_CHOOSER.equals(newIntent.getAction())) {
Intent innerIntent = newIntent.getParcelableExtra(Intent.EXTRA_INTENT);
// At this point, innerIntent is not null. Otherwise, canForward would have returned
// false.
innerIntent.prepareToLeaveUser(callingUserId);
innerIntent.fixUris(callingUserId);
} else {
newIntent.prepareToLeaveUser(callingUserId);
}
newIntent.prepareToLeaveUser(callingUserId);
final ResolveInfo ri = mInjector.resolveActivityAsUser(newIntent, MATCH_DEFAULT_ONLY,
targetUserId);
@@ -153,6 +149,33 @@ public class IntentForwarderActivity extends Activity {
finish();
}
private void launchChooserActivityWithCorrectTab(Intent intentReceived, String className) {
// When showing the sharesheet, instead of forwarding to the other profile,
// we launch the sharesheet in the current user and select the other tab.
// This fixes b/152866292 where the user can not go back to the original profile
// when cross-profile intents are disabled.
int selectedProfile = findSelectedProfile(className);
sanitizeIntent(intentReceived);
intentReceived.putExtra(ChooserActivity.EXTRA_SELECTED_PROFILE, selectedProfile);
Intent innerIntent = intentReceived.getParcelableExtra(Intent.EXTRA_INTENT);
if (innerIntent == null) {
Slog.wtf(TAG, "Cannot start a chooser intent with no extra " + Intent.EXTRA_INTENT);
return;
}
sanitizeIntent(innerIntent);
startActivity(intentReceived);
finish();
}
private int findSelectedProfile(String className) {
if (className.equals(FORWARD_INTENT_TO_PARENT)) {
return ChooserActivity.PROFILE_PERSONAL;
} else if (className.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) {
return ChooserActivity.PROFILE_WORK;
}
return -1;
}
private boolean shouldShowDisclosure(@Nullable ResolveInfo ri, Intent intent) {
if (!isDeviceProvisioned()) {
return false;

View File

@@ -213,13 +213,9 @@ public class IntentForwarderActivityTest {
}
@Test
public void forwardToManagedProfile_canForward_chooserIntent() throws Exception {
public void launchInSameProfile_chooserIntent() {
sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
// Intent can be forwarded.
when(mIPm.canForwardTo(
any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(true);
// Manage profile exists.
List<UserInfo> profiles = new ArrayList<>();
profiles.add(CURRENT_USER_INFO);
@@ -235,10 +231,6 @@ public class IntentForwarderActivityTest {
intent.putExtra(Intent.EXTRA_INTENT, sendIntent);
IntentForwarderWrapperActivity activity = mActivityRule.launchActivity(intent);
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mIPm).canForwardTo(intentCaptor.capture(), eq(TYPE_PLAIN_TEXT), anyInt(), anyInt());
assertEquals(Intent.ACTION_SEND, intentCaptor.getValue().getAction());
assertNotNull(activity.mStartActivityIntent);
assertEquals(Intent.ACTION_CHOOSER, activity.mStartActivityIntent.getAction());
assertNull(activity.mStartActivityIntent.getPackage());
@@ -249,9 +241,9 @@ public class IntentForwarderActivityTest {
assertEquals(Intent.ACTION_SEND, innerIntent.getAction());
assertNull(innerIntent.getComponent());
assertNull(innerIntent.getPackage());
assertEquals(CURRENT_USER_INFO.id, innerIntent.getContentUserHint());
assertEquals(UserHandle.USER_CURRENT, innerIntent.getContentUserHint());
assertEquals(MANAGED_PROFILE_INFO.id, activity.mUserIdActivityLaunchedIn);
assertEquals(CURRENT_USER_INFO.id, activity.mUserIdActivityLaunchedIn);
}
@Test
@@ -655,6 +647,12 @@ public class IntentForwarderActivityTest {
mUserIdActivityLaunchedIn = userId;
}
@Override
public void startActivity(Intent intent) {
mStartActivityIntent = intent;
mUserIdActivityLaunchedIn = getUserId();
}
@Override
protected MetricsLogger getMetricsLogger() {
return mMetricsLogger;