From d273b387e953ba02f79d48e92ef8e8c8e064703b Mon Sep 17 00:00:00 2001 From: Andrey Epin Date: Fri, 2 Dec 2022 10:54:27 -0800 Subject: Fix ChooserActivity crash when launched with a caller-provided target Fix java.lang.UnsupportedOperationException at ShortcutSelectionLogic.addServiceResults() when trying to sort an unmodifiable collection. A new unit test for launcing ChooserActivity with a caller-provided target is added. Fix: 261215405 Test: manual test Test: atest IntentResolverUnitTests Change-Id: I8a28e074044e932753ab4906409cded67f4ccdad --- .../android/intentresolver/ChooserActivity.java | 2 +- .../UnbundledChooserActivityTest.java | 85 ++++++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) (limited to 'java') diff --git a/java/src/com/android/intentresolver/ChooserActivity.java b/java/src/com/android/intentresolver/ChooserActivity.java index fe1df879..ebf0d203 100644 --- a/java/src/com/android/intentresolver/ChooserActivity.java +++ b/java/src/com/android/intentresolver/ChooserActivity.java @@ -1160,7 +1160,7 @@ public class ChooserActivity extends ResolverActivity implements if (mChooserRequest.getCallerChooserTargets().size() > 0) { mChooserMultiProfilePagerAdapter.getActiveListAdapter().addServiceResults( /* origTarget */ null, - mChooserRequest.getCallerChooserTargets(), + new ArrayList<>(mChooserRequest.getCallerChooserTargets()), TARGET_TYPE_DEFAULT, /* directShareShortcutInfoCache */ Collections.emptyMap(), /* directShareAppTargetCache */ Collections.emptyMap()); diff --git a/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java b/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java index da72a749..28b68530 100644 --- a/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java +++ b/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java @@ -78,6 +78,7 @@ import android.graphics.Paint; import android.graphics.drawable.Icon; import android.metrics.LogMaker; import android.net.Uri; +import android.os.Bundle; import android.os.UserHandle; import android.provider.DeviceConfig; import android.service.chooser.ChooserTarget; @@ -1635,6 +1636,90 @@ public class UnbundledChooserActivityTest { is("testTitle1")); } + @Test + public void testLaunchWithCallerProvidedTarget() { + setDeviceConfigProperty( + SystemUiDeviceConfigFlags.APPLY_SHARING_APP_LIMITS_IN_SYSUI, + Boolean.toString(false)); + // Set up resources + ChooserActivityOverrideData.getInstance().resources = Mockito.spy( + InstrumentationRegistry.getInstrumentation().getContext().getResources()); + when( + ChooserActivityOverrideData + .getInstance() + .resources + .getInteger(R.integer.config_maxShortcutTargetsPerApp)) + .thenReturn(1); + + // We need app targets for direct targets to get displayed + List resolvedComponentInfos = createResolvedComponentsForTest(2); + when( + ChooserActivityOverrideData + .getInstance() + .resolverListController + .getResolversForIntent( + Mockito.anyBoolean(), + Mockito.anyBoolean(), + Mockito.anyBoolean(), + Mockito.isA(List.class))) + .thenReturn(resolvedComponentInfos); + + // set caller-provided target + Intent chooserIntent = Intent.createChooser(createSendTextIntent(), null); + String callerTargetLabel = "Caller Target"; + ChooserTarget[] targets = new ChooserTarget[] { + new ChooserTarget( + callerTargetLabel, + Icon.createWithBitmap(createBitmap()), + 0.1f, + resolvedComponentInfos.get(0).name, + new Bundle()) + }; + chooserIntent.putExtra(Intent.EXTRA_CHOOSER_TARGETS, targets); + + // create test shortcut loader factory, remember loaders and their callbacks + SparseArray>> shortcutLoaders = + createShortcutLoaderFactory(); + + // Start activity + final IChooserWrapper activity = (IChooserWrapper) + mActivityRule.launchActivity(chooserIntent); + waitForIdle(); + + // verify that ShortcutLoader was queried + ArgumentCaptor appTargets = + ArgumentCaptor.forClass(DisplayResolveInfo[].class); + verify(shortcutLoaders.get(0).first, times(1)).queryShortcuts(appTargets.capture()); + + // send shortcuts + assertThat( + "Wrong number of app targets", + appTargets.getValue().length, + is(resolvedComponentInfos.size())); + ShortcutLoader.Result result = new ShortcutLoader.Result( + true, + appTargets.getValue(), + new ShortcutLoader.ShortcutResultInfo[0], + new HashMap<>(), + new HashMap<>()); + activity.getMainExecutor().execute(() -> shortcutLoaders.get(0).second.accept(result)); + waitForIdle(); + + final ChooserListAdapter activeAdapter = activity.getAdapter(); + assertThat( + "Chooser should have 3 targets (2 apps, 1 direct)", + activeAdapter.getCount(), + is(3)); + assertThat( + "Chooser should have exactly two selectable direct target", + activeAdapter.getSelectableServiceTargetCount(), + is(1)); + assertThat( + "The display label must match", + activeAdapter.getItem(0).getDisplayLabel(), + is(callerTargetLabel)); + } + @Test public void testUpdateMaxTargetsPerRow_columnCountIsUpdated() throws InterruptedException { updateMaxTargetsPerRowResource(/* targetsPerRow= */ 4); -- cgit v1.2.3-59-g8ed1b