diff options
3 files changed, 104 insertions, 34 deletions
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 3fc3f3e65d37..c4e25b137c0d 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -171,17 +171,6 @@ 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"; @@ -923,15 +912,8 @@ public class ChooserActivity extends ResolverActivity implements } 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 { + int selectedProfile = getSelectedProfileExtra(); + if (selectedProfile == -1) { selectedProfile = getProfileForUser(getUser()); } return selectedProfile; diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java index fca156a97a83..e65d1fe9ce53 100644 --- a/core/java/com/android/internal/app/IntentForwarderActivity.java +++ b/core/java/com/android/internal/app/IntentForwarderActivity.java @@ -18,6 +18,8 @@ package com.android.internal.app; import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY; +import static com.android.internal.app.ResolverActivity.EXTRA_SELECTED_PROFILE; + import android.annotation.Nullable; import android.annotation.StringRes; import android.app.Activity; @@ -26,6 +28,7 @@ import android.app.ActivityThread; import android.app.AppGlobals; import android.app.admin.DevicePolicyManager; import android.compat.annotation.UnsupportedAppUsage; +import android.content.ComponentName; import android.content.ContentResolver; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -74,6 +77,9 @@ public class IntentForwarderActivity extends Activity { private static final String TEL_SCHEME = "tel"; + private static final ComponentName RESOLVER_COMPONENT_NAME = + new ComponentName("android", ResolverActivity.class.getName()); + private Injector mInjector; private MetricsLogger mMetricsLogger; @@ -136,21 +142,50 @@ public class IntentForwarderActivity extends Activity { } newIntent.prepareToLeaveUser(callingUserId); - maybeShowDisclosureAsync(intentReceived, newIntent, targetUserId, userMessageId); - CompletableFuture.runAsync(() -> - startActivityAsCaller(newIntent, targetUserId), mExecutorService) - .thenAcceptAsync(result -> finish(), getApplicationContext().getMainExecutor()); + final CompletableFuture<ResolveInfo> targetResolveInfoFuture = + mInjector.resolveActivityAsUser(newIntent, MATCH_DEFAULT_ONLY, targetUserId); + targetResolveInfoFuture + .thenApplyAsync(targetResolveInfo -> { + if (isResolverActivityResolveInfo(targetResolveInfo)) { + launchResolverActivityWithCorrectTab(intentReceived, className, newIntent, + callingUserId, targetUserId); + return targetResolveInfo; + } + startActivityAsCaller(newIntent, targetUserId); + return targetResolveInfo; + }, mExecutorService) + .thenAcceptAsync(result -> { + maybeShowDisclosure(intentReceived, result, userMessageId); + finish(); + }, getApplicationContext().getMainExecutor()); } - private void maybeShowDisclosureAsync( - Intent intentReceived, Intent newIntent, int userId, int messageId) { - final CompletableFuture<ResolveInfo> resolveInfoFuture = - mInjector.resolveActivityAsUser(newIntent, MATCH_DEFAULT_ONLY, userId); - resolveInfoFuture.thenAcceptAsync(ri -> { - if (shouldShowDisclosure(ri, intentReceived)) { - mInjector.showToast(messageId, Toast.LENGTH_LONG); - } - }, getApplicationContext().getMainExecutor()); + private boolean isIntentForwarderResolveInfo(ResolveInfo resolveInfo) { + if (resolveInfo == null) { + return false; + } + ActivityInfo activityInfo = resolveInfo.activityInfo; + if (activityInfo == null) { + return false; + } + if (!"android".equals(activityInfo.packageName)) { + return false; + } + return activityInfo.name.equals(FORWARD_INTENT_TO_PARENT) + || activityInfo.name.equals(FORWARD_INTENT_TO_MANAGED_PROFILE); + } + + private boolean isResolverActivityResolveInfo(@Nullable ResolveInfo resolveInfo) { + return resolveInfo != null + && resolveInfo.activityInfo != null + && RESOLVER_COMPONENT_NAME.equals(resolveInfo.activityInfo.getComponentName()); + } + + private void maybeShowDisclosure( + Intent intentReceived, ResolveInfo resolveInfo, int messageId) { + if (shouldShowDisclosure(resolveInfo, intentReceived)) { + mInjector.showToast(messageId, Toast.LENGTH_LONG); + } } private void startActivityAsCaller(Intent newIntent, int userId) { @@ -185,7 +220,7 @@ public class IntentForwarderActivity extends Activity { // when cross-profile intents are disabled. int selectedProfile = findSelectedProfile(className); sanitizeIntent(intentReceived); - intentReceived.putExtra(ChooserActivity.EXTRA_SELECTED_PROFILE, selectedProfile); + intentReceived.putExtra(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); @@ -196,6 +231,25 @@ public class IntentForwarderActivity extends Activity { finish(); } + private void launchResolverActivityWithCorrectTab(Intent intentReceived, String className, + Intent newIntent, int callingUserId, int targetUserId) { + // When showing the intent resolver, instead of forwarding to the other profile, + // we launch it in the current user and select the other tab. This fixes b/155874820. + // + // In the case when there are 0 targets in the current profile and >1 apps in the other + // profile, the package manager launches the intent resolver in the other profile. + // If that's the case, we launch the resolver in the target user instead (other profile). + ResolveInfo callingResolveInfo = mInjector.resolveActivityAsUser( + newIntent, MATCH_DEFAULT_ONLY, callingUserId).join(); + int userId = isIntentForwarderResolveInfo(callingResolveInfo) + ? targetUserId : callingUserId; + int selectedProfile = findSelectedProfile(className); + sanitizeIntent(intentReceived); + intentReceived.putExtra(EXTRA_SELECTED_PROFILE, selectedProfile); + startActivityAsCaller(intentReceived, null, null, false, userId); + finish(); + } + private int findSelectedProfile(String className) { if (className.equals(FORWARD_INTENT_TO_PARENT)) { return ChooserActivity.PROFILE_PERSONAL; diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 9c2df131d11a..08ae6c227316 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -179,6 +179,17 @@ public class ResolverActivity extends Activity implements // Intent extra for connected audio devices public static final String EXTRA_IS_AUDIO_CAPTURE_DEVICE = "is_audio_capture_device"; + /** + * 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.ResolverActivity.EXTRA_SELECTED_PROFILE"; + + static final int PROFILE_PERSONAL = AbstractMultiProfilePagerAdapter.PROFILE_PERSONAL; + static final int PROFILE_WORK = AbstractMultiProfilePagerAdapter.PROFILE_WORK; + private BroadcastReceiver mWorkProfileStateReceiver; private UserHandle mHeaderCreatorUser; @@ -475,6 +486,10 @@ public class ResolverActivity extends Activity implements selectedProfile = PROFILE_WORK; } } + int selectedProfileExtra = getSelectedProfileExtra(); + if (selectedProfileExtra != -1) { + selectedProfile = selectedProfileExtra; + } // We only show the default app for the profile of the current user. The filterLastUsed // flag determines whether to show a default app and that app is not shown in the // resolver list. So filterLastUsed should be false for the other profile. @@ -508,6 +523,25 @@ public class ResolverActivity extends Activity implements } /** + * Returns {@link #PROFILE_PERSONAL} or {@link #PROFILE_WORK} if the {@link + * #EXTRA_SELECTED_PROFILE} extra was supplied, or {@code -1} if no extra was supplied. + * @throws IllegalArgumentException if the value passed to the {@link #EXTRA_SELECTED_PROFILE} + * extra is not {@link #PROFILE_PERSONAL} or {@link #PROFILE_WORK} + */ + int getSelectedProfileExtra() { + int selectedProfile = -1; + 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 ResolverActivity.PROFILE_PERSONAL or " + + "ResolverActivity.PROFILE_WORK."); + } + } + return selectedProfile; + } + + /** * Returns the user id of the user that the starting intent originated from. * <p>This is not necessarily equal to {@link #getUserId()} or {@link UserHandle#myUserId()}, * as there are edge cases when the intent resolver is launched in the other profile. |