App Cloning fixes for Sharesheet

This Cl adds the following:
1. Fixes a bug where if a cloned app has initialIntents and launches sharesheet,
   initialIntents would always resolve in user 0 (personalProfileHandle) instead
   of clonedProfileHandle
2. TODOs mentioned in ag/20982903 addressed.
3. Test cases added.

Test: atest ChooserActivityTest, atest ResolverActivityTest
Change-Id: Iedb24d8775d08319b136d96d7ffff1665a1b0748
This commit is contained in:
Himanshu Gupta
2023-01-24 18:01:39 +00:00
parent 2aebeda456
commit b8362e906f
11 changed files with 154 additions and 93 deletions

View File

@@ -2525,8 +2525,7 @@ public class ChooserActivity extends ResolverActivity implements
List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList,
boolean filterLastUsed, UserHandle userHandle) {
ChooserListAdapter chooserListAdapter = createChooserListAdapter(context, payloadIntents,
initialIntents, rList, filterLastUsed,
createListController(userHandle));
initialIntents, rList, filterLastUsed, userHandle);
AppPredictor.Callback appPredictorCallback = createAppPredictorCallback(chooserListAdapter);
AppPredictor appPredictor = setupAppPredictorForUser(userHandle, appPredictorCallback);
chooserListAdapter.setAppPredictor(appPredictor);
@@ -2536,12 +2535,18 @@ public class ChooserActivity extends ResolverActivity implements
@VisibleForTesting
public ChooserListAdapter createChooserListAdapter(Context context,
List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList,
boolean filterLastUsed, ResolverListController resolverListController) {
List<Intent> payloadIntents,
Intent[] initialIntents,
List<ResolveInfo> rList,
boolean filterLastUsed,
UserHandle userHandle) {
UserHandle initialIntentsUserSpace = isLaunchedAsCloneProfile()
&& userHandle.equals(getPersonalProfileUserHandle())
? getCloneProfileUserHandle() : userHandle;
return new ChooserListAdapter(context, payloadIntents, initialIntents, rList,
filterLastUsed, resolverListController, this,
filterLastUsed, createListController(userHandle), this,
this, context.getPackageManager(),
getChooserActivityLogger());
getChooserActivityLogger(), initialIntentsUserSpace);
}
@VisibleForTesting

View File

@@ -105,6 +105,9 @@ public class ChooserListAdapter extends ResolverListAdapter {
private AppPredictor mAppPredictor;
private AppPredictor.Callback mAppPredictorCallback;
// Represents the UserSpace in which the Initial Intents should be resolved.
private final UserHandle mInitialIntentsUserSpace;
// For pinned direct share labels, if the text spans multiple lines, the TextView will consume
// the full width, even if the characters actually take up less than that. Measure the actual
// line widths and constrain the View's width based upon that so that the pin doesn't end up
@@ -142,11 +145,12 @@ public class ChooserListAdapter extends ResolverListAdapter {
ChooserListCommunicator chooserListCommunicator,
SelectableTargetInfo.SelectableTargetInfoCommunicator selectableTargetInfoCommunicator,
PackageManager packageManager,
ChooserActivityLogger chooserActivityLogger) {
ChooserActivityLogger chooserActivityLogger,
UserHandle initialIntentsUserSpace) {
// Don't send the initial intents through the shared ResolverActivity path,
// we want to separate them into a different section.
super(context, payloadIntents, null, rList, filterLastUsed,
resolverListController, chooserListCommunicator, false);
resolverListController, chooserListCommunicator, false, initialIntentsUserSpace);
mMaxShortcutTargetsPerApp =
context.getResources().getInteger(R.integer.config_maxShortcutTargetsPerApp);
@@ -154,6 +158,7 @@ public class ChooserListAdapter extends ResolverListAdapter {
createPlaceHolders();
mSelectableTargetInfoCommunicator = selectableTargetInfoCommunicator;
mChooserActivityLogger = chooserActivityLogger;
mInitialIntentsUserSpace = initialIntentsUserSpace;
if (initialIntents != null) {
for (int i = 0; i < initialIntents.length; i++) {
@@ -197,7 +202,7 @@ public class ChooserListAdapter extends ResolverListAdapter {
ri.nonLocalizedLabel = li.getNonLocalizedLabel();
ri.icon = li.getIconResource();
ri.iconResourceId = ri.icon;
ri.userHandle = getUserHandle();
ri.userHandle = mInitialIntentsUserSpace;
}
if (userManager.isManagedProfile()) {
ri.noResourceId = true;
@@ -351,6 +356,10 @@ public class ChooserListAdapter extends ResolverListAdapter {
// Consolidate multiple targets from same app.
Map<String, DisplayResolveInfo> consolidated = new HashMap<>();
for (DisplayResolveInfo info : allTargets) {
if (info.getResolveInfo().userHandle == null) {
Log.e(TAG, "ResolveInfo with null UserHandle found: "
+ info.getResolveInfo());
}
String resolvedTarget = info.getResolvedComponentName().getPackageName()
+ '#' + info.getDisplayLabel()
+ '#' + ResolverActivity.getResolveInfoUserHandle(

View File

@@ -33,6 +33,8 @@ import static android.stats.devicepolicy.nano.DevicePolicyEnums.RESOLVER_EMPTY_S
import static android.stats.devicepolicy.nano.DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_WORK;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED;
import android.annotation.Nullable;
import android.annotation.StringRes;
import android.annotation.UiThread;
@@ -780,7 +782,7 @@ public class ResolverActivity extends Activity implements
return getCloneProfileUserHandle() != null;
}
private boolean isLaunchedAsCloneProfile() {
protected final boolean isLaunchedAsCloneProfile() {
return hasCloneProfile()
&& (UserHandle.myUserId() == getCloneProfileUserHandle().getIdentifier());
}
@@ -1517,9 +1519,7 @@ public class ResolverActivity extends Activity implements
safelyStartActivityAsUser(cti, user, null);
}
// TODO: Make method public final.
@VisibleForTesting
protected void safelyStartActivityAsUser(
protected final void safelyStartActivityAsUser(
TargetInfo cti, UserHandle user, @Nullable Bundle options) {
// We're dispatching intents that might be coming from legacy apps, so
// don't kill ourselves.
@@ -1609,9 +1609,12 @@ public class ResolverActivity extends Activity implements
Intent startIntent = getIntent();
boolean isAudioCaptureDevice =
startIntent.getBooleanExtra(EXTRA_IS_AUDIO_CAPTURE_DEVICE, false);
UserHandle initialIntentsUserSpace = isLaunchedAsCloneProfile()
&& userHandle.equals(getPersonalProfileUserHandle())
? getCloneProfileUserHandle() : userHandle;
return new ResolverListAdapter(context, payloadIntents, initialIntents, rList,
filterLastUsed, createListController(userHandle), this,
isAudioCaptureDevice);
isAudioCaptureDevice, initialIntentsUserSpace);
}
@VisibleForTesting
@@ -2535,20 +2538,18 @@ public class ResolverActivity extends Activity implements
return queryIntentsUser;
}
/**
* This function is temporary in nature, and its usages will be replaced with just
* resolveInfo.userHandle, once it is available, once sharesheet is stable.
*/
public static UserHandle getResolveInfoUserHandle(ResolveInfo resolveInfo,
UserHandle predictedHandle) {
return resolveInfo.userHandle;
}
/**
* Returns the {@link List} of {@link UserHandle} to pass on to the
* {@link ResolverRankerServiceResolverComparator} as per the provided {@code userHandle}.
*/
protected final List<UserHandle> getResolverRankerServiceUserHandleList(UserHandle userHandle) {
@VisibleForTesting(visibility = PROTECTED)
public final List<UserHandle> getResolverRankerServiceUserHandleList(UserHandle userHandle) {
return getResolverRankerServiceUserHandleListInternal(userHandle);
}
@VisibleForTesting
protected List<UserHandle> getResolverRankerServiceUserHandleListInternal(UserHandle
userHandle) {
List<UserHandle> userList = new ArrayList<>();
userList.add(userHandle);
// Add clonedProfileUserHandle to the list only if we are:
@@ -2560,4 +2561,16 @@ public class ResolverActivity extends Activity implements
}
return userList;
}
/**
* This function is temporary in nature, and its usages will be replaced with just
* resolveInfo.userHandle, once it is available, once sharesheet is stable.
*/
public static UserHandle getResolveInfoUserHandle(ResolveInfo resolveInfo,
UserHandle predictedHandle) {
if (resolveInfo.userHandle == null) {
Log.e(TAG, "ResolveInfo with null UserHandle found: " + resolveInfo);
}
return resolveInfo.userHandle;
}
}

View File

@@ -91,13 +91,16 @@ public class ResolverListAdapter extends BaseAdapter {
private boolean mIsTabLoaded;
private final Map<DisplayResolveInfo, LoadIconTask> mIconLoaders = new HashMap<>();
private final Map<DisplayResolveInfo, LoadLabelTask> mLabelLoaders = new HashMap<>();
// Represents the UserSpace in which the Initial Intents should be resolved.
private final UserHandle mInitialIntentsUserSpace;
public ResolverListAdapter(Context context, List<Intent> payloadIntents,
Intent[] initialIntents, List<ResolveInfo> rList,
boolean filterLastUsed,
ResolverListController resolverListController,
ResolverListCommunicator resolverListCommunicator,
boolean isAudioCaptureDevice) {
boolean isAudioCaptureDevice,
UserHandle initialIntentsUserSpace) {
mContext = context;
mIntents = payloadIntents;
mInitialIntents = initialIntents;
@@ -111,6 +114,11 @@ public class ResolverListAdapter extends BaseAdapter {
mIsAudioCaptureDevice = isAudioCaptureDevice;
final ActivityManager am = (ActivityManager) mContext.getSystemService(ACTIVITY_SERVICE);
mIconDpi = am.getLauncherLargeIconDensity();
mInitialIntentsUserSpace = initialIntentsUserSpace;
}
public ResolverListController getResolverListController() {
return mResolverListController;
}
public void handlePackagesChanged() {
@@ -439,7 +447,7 @@ public class ResolverListAdapter extends BaseAdapter {
ri.nonLocalizedLabel = li.getNonLocalizedLabel();
ri.icon = li.getIconResource();
ri.iconResourceId = ri.icon;
ri.userHandle = getUserHandle();
ri.userHandle = mInitialIntentsUserSpace;
}
if (userManager.isManagedProfile()) {
ri.noResourceId = true;

View File

@@ -53,7 +53,7 @@ public class ChooserActivityOverrideData {
@SuppressWarnings("Since15")
public Function<PackageManager, PackageManager> createPackageManager;
public Function<TargetInfo, Boolean> onSafelyStartCallback;
public Function<TargetInfo, Boolean> onSafelyStartInternalCallback;
public Function<ChooserListAdapter, Void> onQueryDirectShareTargets;
public BiFunction<
IChooserWrapper, ChooserListAdapter, Pair<Integer, ChooserActivity.ServiceResultInfo[]>>
@@ -82,7 +82,7 @@ public class ChooserActivityOverrideData {
public PackageManager packageManager;
public void reset() {
onSafelyStartCallback = null;
onSafelyStartInternalCallback = null;
onQueryDirectShareTargets = null;
directShareTargets = null;
isVoiceInteraction = null;

View File

@@ -446,7 +446,7 @@ public class ChooserActivityTest {
onView(withIdFromRuntimeResource("profile_button")).check(doesNotExist());
ResolveInfo[] chosen = new ResolveInfo[1];
ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
return true;
};
@@ -501,7 +501,7 @@ public class ChooserActivityTest {
assertThat(activity.getAdapter().getCount(), is(6));
ResolveInfo[] chosen = new ResolveInfo[1];
ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
return true;
};
@@ -541,7 +541,7 @@ public class ChooserActivityTest {
verify(ChooserActivityOverrideData.getInstance().resolverListController, times(1))
.topK(any(List.class), anyInt());
assertThat(activity.getIsSelected(), is(false));
ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
return true;
};
ResolveInfo toChoose = resolvedComponentInfos.get(0).getResolveInfoAt(0);
@@ -592,7 +592,7 @@ public class ChooserActivityTest {
@Test
public void autoLaunchSingleResult() throws InterruptedException {
ResolveInfo[] chosen = new ResolveInfo[1];
ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
return true;
};
@@ -638,7 +638,7 @@ public class ChooserActivityTest {
assertThat(activity.getAdapter().getCount(), is(1));
ResolveInfo[] chosen = new ResolveInfo[1];
ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
return true;
};
@@ -681,7 +681,7 @@ public class ChooserActivityTest {
assertThat(activity.getAdapter().getCount(), is(2));
ResolveInfo[] chosen = new ResolveInfo[1];
ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
return true;
};
@@ -719,7 +719,7 @@ public class ChooserActivityTest {
assertThat(activity.getAdapter().getCount(), is(2));
ResolveInfo[] chosen = new ResolveInfo[1];
ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
return true;
};
@@ -1949,7 +1949,7 @@ public class ChooserActivityTest {
Intent sendIntent = createSendTextIntent();
sendIntent.setType(TEST_MIME_TYPE);
ResolveInfo[] chosen = new ResolveInfo[1];
ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
return true;
};
@@ -2127,7 +2127,7 @@ public class ChooserActivityTest {
onView(withIdFromRuntimeResource("profile_button")).check(doesNotExist());
ResolveInfo[] chosen = new ResolveInfo[1];
ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
return true;
};
@@ -2513,7 +2513,7 @@ public class ChooserActivityTest {
Intent sendIntent = createSendTextIntent();
sendIntent.setType(TEST_MIME_TYPE);
ResolveInfo[] chosen = new ResolveInfo[1];
ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
return true;
};
@@ -2543,7 +2543,7 @@ public class ChooserActivityTest {
Intent sendIntent = createSendTextIntent();
sendIntent.setType(TEST_MIME_TYPE);
ResolveInfo[] chosen = new ResolveInfo[1];
ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
return true;
};
@@ -2569,7 +2569,7 @@ public class ChooserActivityTest {
setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
Intent sendIntent = createSendTextIntent();
ResolveInfo[] chosen = new ResolveInfo[1];
ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
return true;
};
@@ -2597,7 +2597,7 @@ public class ChooserActivityTest {
Intent chooserIntent = createChooserIntent(createSendTextIntent(),
new Intent[] {new Intent("action.fake")});
ResolveInfo[] chosen = new ResolveInfo[1];
ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
return true;
};

View File

@@ -22,6 +22,7 @@ import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.os.Bundle
import android.os.UserHandle
import android.service.chooser.ChooserTarget
import android.view.View
import android.widget.FrameLayout
@@ -73,7 +74,8 @@ class ChooserListAdapterTest {
selectableTargetInfoCommunicator,
packageManager,
chooserActivityLogger,
taskProvider
null,
taskProvider,
)
@Test
@@ -160,6 +162,7 @@ private class ChooserListAdapterOverride(
selectableTargetInfoCommunicator: SelectableTargetInfoCommunicator?,
packageManager: PackageManager?,
chooserActivityLogger: ChooserActivityLogger?,
initialIntentsUserHandle: UserHandle?,
private val taskProvider: (SelectableTargetInfo?) -> LoadDirectShareIconTask
) : ChooserListAdapter(
context,
@@ -171,7 +174,8 @@ private class ChooserListAdapterOverride(
chooserListCommunicator,
selectableTargetInfoCommunicator,
packageManager,
chooserActivityLogger
chooserActivityLogger,
initialIntentsUserHandle,
) {
override fun createLoadDirectShareIconTask(
info: SelectableTargetInfo?

View File

@@ -64,14 +64,14 @@ public class ChooserWrapperActivity extends ChooserActivity implements IChooserW
@Override
public ChooserListAdapter createChooserListAdapter(Context context, List<Intent> payloadIntents,
Intent[] initialIntents, List<ResolveInfo> rList, boolean filterLastUsed,
ResolverListController resolverListController) {
UserHandle userHandle) {
PackageManager packageManager =
sOverrides.packageManager == null ? context.getPackageManager()
: sOverrides.packageManager;
return new ChooserListAdapter(context, payloadIntents, initialIntents, rList,
filterLastUsed, resolverListController,
filterLastUsed, createListController(userHandle),
this, this, packageManager,
getChooserActivityLogger());
getChooserActivityLogger(), userHandle);
}
@Override
@@ -143,15 +143,14 @@ public class ChooserWrapperActivity extends ChooserActivity implements IChooserW
return super.createQuietModeManager();
}
// TODO: Remove this and override safelyStartActivityInternal() instead.
@Override
public void safelyStartActivityAsUser(TargetInfo cti, UserHandle user,
public void safelyStartActivityInternal(TargetInfo cti, UserHandle user,
@Nullable Bundle options) {
if (sOverrides.onSafelyStartCallback != null &&
sOverrides.onSafelyStartCallback.apply(cti)) {
if (sOverrides.onSafelyStartInternalCallback != null
&& sOverrides.onSafelyStartInternalCallback.apply(cti)) {
return;
}
super.safelyStartActivityAsUser(cti, user, options);
super.safelyStartActivityInternal(cti, user, options);
}
@Override

View File

@@ -64,6 +64,8 @@ import com.android.internal.app.ResolverListAdapter.ActivityInfoPresentationGett
import com.android.internal.app.ResolverListAdapter.ResolveInfoPresentationGetter;
import com.android.internal.widget.ResolverDrawerLayout;
import com.google.android.collect.Lists;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
@@ -110,8 +112,8 @@ public class ResolverActivityTest {
assertThat(activity.getAdapter().getCount(), is(2));
ResolveInfo[] chosen = new ResolveInfo[1];
sOverrides.onSafelyStartCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
sOverrides.onSafelyStartInternalCallback = result -> {
chosen[0] = result.first.getResolveInfo();
return true;
};
@@ -226,8 +228,8 @@ public class ResolverActivityTest {
assertThat(activity.getAdapter().getPlaceholderCount(), is(1));
ResolveInfo[] chosen = new ResolveInfo[1];
sOverrides.onSafelyStartCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
sOverrides.onSafelyStartInternalCallback = result -> {
chosen[0] = result.first.getResolveInfo();
return true;
};
@@ -258,8 +260,8 @@ public class ResolverActivityTest {
assertThat(activity.getAdapter().getCount(), is(1));
ResolveInfo[] chosen = new ResolveInfo[1];
sOverrides.onSafelyStartCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
sOverrides.onSafelyStartInternalCallback = result -> {
chosen[0] = result.first.getResolveInfo();
return true;
};
// Make a stable copy of the components as the original list may be modified
@@ -298,8 +300,8 @@ public class ResolverActivityTest {
assertThat(activity.getAdapter().getCount(), is(2));
ResolveInfo[] chosen = new ResolveInfo[1];
sOverrides.onSafelyStartCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
sOverrides.onSafelyStartInternalCallback = result -> {
chosen[0] = result.first.getResolveInfo();
return true;
};
@@ -345,8 +347,8 @@ public class ResolverActivityTest {
assertThat(activity.getAdapter().getCount(), is(2));
ResolveInfo[] chosen = new ResolveInfo[1];
sOverrides.onSafelyStartCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
sOverrides.onSafelyStartInternalCallback = result -> {
chosen[0] = result.first.getResolveInfo();
return true;
};
@@ -531,8 +533,8 @@ public class ResolverActivityTest {
setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
Intent sendIntent = createSendImageIntent();
ResolveInfo[] chosen = new ResolveInfo[1];
sOverrides.onSafelyStartCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
sOverrides.onSafelyStartInternalCallback = result -> {
chosen[0] = result.first.getResolveInfo();
return true;
};
@@ -634,8 +636,8 @@ public class ResolverActivityTest {
setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
Intent sendIntent = createSendImageIntent();
ResolveInfo[] chosen = new ResolveInfo[1];
sOverrides.onSafelyStartCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
sOverrides.onSafelyStartInternalCallback = result -> {
chosen[0] = result.first.getResolveInfo();
return true;
};
@@ -848,8 +850,8 @@ public class ResolverActivityTest {
Intent sendIntent = createSendImageIntent();
sendIntent.setType("TestType");
ResolveInfo[] chosen = new ResolveInfo[1];
sOverrides.onSafelyStartCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
sOverrides.onSafelyStartInternalCallback = result -> {
chosen[0] = result.first.getResolveInfo();
return true;
};
waitForIdle();
@@ -873,8 +875,8 @@ public class ResolverActivityTest {
Intent sendIntent = createSendImageIntent();
sendIntent.setType("TestType");
ResolveInfo[] chosen = new ResolveInfo[1];
sOverrides.onSafelyStartCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
sOverrides.onSafelyStartInternalCallback = result -> {
chosen[0] = result.first.getResolveInfo();
return true;
};
waitForIdle();
@@ -902,8 +904,8 @@ public class ResolverActivityTest {
Intent sendIntent = createSendImageIntent();
sendIntent.setType("TestType");
ResolveInfo[] chosen = new ResolveInfo[1];
sOverrides.onSafelyStartCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
sOverrides.onSafelyStartInternalCallback = result -> {
chosen[0] = result.first.getResolveInfo();
return true;
};
@@ -1072,8 +1074,8 @@ public class ResolverActivityTest {
Intent sendIntent = createSendImageIntent();
sendIntent.setType("TestType");
final UserHandle[] selectedActivityUserHandle = new UserHandle[1];
sOverrides.onSafelyStartInternalCallback = userHandle -> {
selectedActivityUserHandle[0] = userHandle;
sOverrides.onSafelyStartInternalCallback = result -> {
selectedActivityUserHandle[0] = result.second;
return true;
};
@@ -1109,8 +1111,8 @@ public class ResolverActivityTest {
Intent sendIntent = createSendImageIntent();
sendIntent.setType("TestType");
final UserHandle[] selectedActivityUserHandle = new UserHandle[1];
sOverrides.onSafelyStartInternalCallback = userHandle -> {
selectedActivityUserHandle[0] = userHandle;
sOverrides.onSafelyStartInternalCallback = result -> {
selectedActivityUserHandle[0] = result.second;
return true;
};
@@ -1129,6 +1131,31 @@ public class ResolverActivityTest {
assertThat(selectedActivityUserHandle[0], is(activity.getAdapter().getUserHandle()));
}
@Test
public void testClonedProfilePresent_personalProfileResolverComparatorHasCorrectUsers()
throws Exception {
// enable cloneProfile
markCloneProfileUserAvailable();
List<ResolvedComponentInfo> resolvedComponentInfos =
createResolvedComponentsWithCloneProfileForTest(
3,
PERSONAL_USER_HANDLE,
sOverrides.cloneProfileUserHandle);
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
Mockito.anyBoolean(),
Mockito.anyBoolean(),
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
Intent sendIntent = createSendImageIntent();
final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
waitForIdle();
List<UserHandle> result = activity
.getResolverRankerServiceUserHandleList(PERSONAL_USER_HANDLE);
assertTrue(result.containsAll(Lists.newArrayList(PERSONAL_USER_HANDLE,
sOverrides.cloneProfileUserHandle)));
}
private Intent createSendImageIntent() {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);

View File

@@ -29,6 +29,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.UserHandle;
import android.util.Pair;
import com.android.internal.app.AbstractMultiProfilePagerAdapter.CrossProfileIntentsChecker;
import com.android.internal.app.AbstractMultiProfilePagerAdapter.QuietModeManager;
@@ -53,7 +54,7 @@ public class ResolverWrapperActivity extends ResolverActivity {
List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList,
boolean filterLastUsed, UserHandle userHandle) {
return new ResolverWrapperAdapter(context, payloadIntents, initialIntents, rList,
filterLastUsed, createListController(userHandle), this);
filterLastUsed, createListController(userHandle), this, userHandle);
}
@Override
@@ -95,22 +96,11 @@ public class ResolverWrapperActivity extends ResolverActivity {
return super.isVoiceInteraction();
}
// TODO: Remove this and override safelyStartActivityInternal() instead.
@Override
public void safelyStartActivityAsUser(TargetInfo cti, UserHandle user,
@Nullable Bundle options) {
if (sOverrides.onSafelyStartCallback != null &&
sOverrides.onSafelyStartCallback.apply(cti)) {
return;
}
super.safelyStartActivityAsUser(cti, user, options);
}
@Override
public void safelyStartActivityInternal(TargetInfo cti, UserHandle user,
@Nullable Bundle options) {
if (sOverrides.onSafelyStartInternalCallback != null
&& sOverrides.onSafelyStartInternalCallback.apply(user)) {
&& sOverrides.onSafelyStartInternalCallback.apply(new Pair<>(cti, user))) {
return;
}
super.safelyStartActivityInternal(cti, user, options);
@@ -166,6 +156,12 @@ public class ResolverWrapperActivity extends ResolverActivity {
super.startActivityAsUser(intent, options, user);
}
@Override
protected List<UserHandle> getResolverRankerServiceUserHandleListInternal(UserHandle
userHandle) {
return super.getResolverRankerServiceUserHandleListInternal(userHandle);
}
/**
* We cannot directly mock the activity created since instrumentation creates it.
* <p>
@@ -174,8 +170,7 @@ public class ResolverWrapperActivity extends ResolverActivity {
static class OverrideData {
@SuppressWarnings("Since15")
public Function<PackageManager, PackageManager> createPackageManager;
public Function<TargetInfo, Boolean> onSafelyStartCallback;
public Function<UserHandle, Boolean> onSafelyStartInternalCallback;
public Function<Pair<TargetInfo, UserHandle>, Boolean> onSafelyStartInternalCallback;
public ResolverListController resolverListController;
public ResolverListController workResolverListController;
public Boolean isVoiceInteraction;
@@ -189,7 +184,6 @@ public class ResolverWrapperActivity extends ResolverActivity {
public CrossProfileIntentsChecker mCrossProfileIntentsChecker;
public void reset() {
onSafelyStartCallback = null;
onSafelyStartInternalCallback = null;
isVoiceInteraction = null;
createPackageManager = null;

View File

@@ -19,6 +19,7 @@ package com.android.internal.app;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.os.UserHandle;
import androidx.test.espresso.idling.CountingIdlingResource;
@@ -36,9 +37,10 @@ public class ResolverWrapperAdapter extends ResolverListAdapter {
Intent[] initialIntents,
List<ResolveInfo> rList, boolean filterLastUsed,
ResolverListController resolverListController,
ResolverListCommunicator resolverListCommunicator) {
ResolverListCommunicator resolverListCommunicator,
UserHandle initialIntentsUserHandle) {
super(context, payloadIntents, initialIntents, rList, filterLastUsed,
resolverListController, resolverListCommunicator, false);
resolverListController, resolverListCommunicator, false, initialIntentsUserHandle);
}
public CountingIdlingResource getLabelIdlingResource() {