Loading core/java/com/android/internal/app/ChooserActivity.java +2 −20 Original line number Diff line number Diff line Loading @@ -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"; Loading Loading @@ -928,15 +917,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; Loading core/java/com/android/internal/app/IntentForwarderActivity.java +68 −14 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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()); } 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)) { 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 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); } }, getApplicationContext().getMainExecutor()); } private void startActivityAsCaller(Intent newIntent, int userId) { Loading Loading @@ -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); Loading @@ -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; Loading core/java/com/android/internal/app/ResolverActivity.java +34 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -511,6 +526,25 @@ public class ResolverActivity extends Activity implements return R.style.Theme_DeviceDefault_Resolver; } /** * 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()}, Loading Loading
core/java/com/android/internal/app/ChooserActivity.java +2 −20 Original line number Diff line number Diff line Loading @@ -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"; Loading Loading @@ -928,15 +917,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; Loading
core/java/com/android/internal/app/IntentForwarderActivity.java +68 −14 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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()); } 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)) { 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 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); } }, getApplicationContext().getMainExecutor()); } private void startActivityAsCaller(Intent newIntent, int userId) { Loading Loading @@ -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); Loading @@ -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; Loading
core/java/com/android/internal/app/ResolverActivity.java +34 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -511,6 +526,25 @@ public class ResolverActivity extends Activity implements return R.style.Theme_DeviceDefault_Resolver; } /** * 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()}, Loading