From c75813909526b02c866afbbdf005859e97b3ee59 Mon Sep 17 00:00:00 2001 From: arangelov Date: Tue, 7 Apr 2020 17:10:36 +0100 Subject: [PATCH] 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 --- .../android/internal/app/ChooserActivity.java | 47 ++++++++++++++++++- .../internal/app/IntentForwarderActivity.java | 41 ++++++++++++---- .../app/IntentForwarderActivityTest.java | 20 ++++---- 3 files changed, 86 insertions(+), 22 deletions(-) diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index c82ab6c79e9db..3e7f24b034ac3 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -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. + *

Can only be used if there is a work profile. + *

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(); diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java index 9bdfa4ad4e438..36eecfb685e8f 100644 --- a/core/java/com/android/internal/app/IntentForwarderActivity.java +++ b/core/java/com/android/internal/app/IntentForwarderActivity.java @@ -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; diff --git a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java index 8cf146ea801d2..769c578356628 100644 --- a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java @@ -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 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 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;