Merge "Launch intent resolver in same profile when used for sharing" into rvc-dev

This commit is contained in:
Antoan Angelov
2020-05-27 20:08:29 +00:00
committed by Android (Google) Code Review
3 changed files with 104 additions and 34 deletions

View File

@@ -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";
@@ -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;

View File

@@ -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;

View File

@@ -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.
@@ -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()},