From c9544a7e92037f44a1ad69e04a0987bf8c0c9fbd Mon Sep 17 00:00:00 2001 From: Matt Pietal Date: Wed, 13 May 2020 21:16:38 -0400 Subject: [PATCH] Sharesheet - Fix app stacking When there was greater than 2 candidates for app stacking, the prior targets would get dropped. Bug: 156220800 Test: atest ChooserActivityTest Change-Id: Ia8494bb81e95c5415d080148a0c4f98bd243c142 --- .../internal/app/ChooserListAdapter.java | 17 +++--- .../internal/app/ChooserActivityTest.java | 54 +++++++++++++++++++ 2 files changed, 64 insertions(+), 7 deletions(-) diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java index f426bc0ecbb53..14a2d379ced61 100644 --- a/core/java/com/android/internal/app/ChooserListAdapter.java +++ b/core/java/com/android/internal/app/ChooserListAdapter.java @@ -262,14 +262,17 @@ public class ChooserListAdapter extends ResolverListAdapter { Map consolidated = new HashMap<>(); for (DisplayResolveInfo info : mDisplayList) { String packageName = info.getResolvedComponentName().getPackageName(); - if (consolidated.get(packageName) != null) { - // create consolidated target - MultiDisplayResolveInfo multiDisplayResolveInfo = - new MultiDisplayResolveInfo(packageName, info); - multiDisplayResolveInfo.addTarget(consolidated.get(packageName)); - consolidated.put(packageName, multiDisplayResolveInfo); - } else { + DisplayResolveInfo multiDri = consolidated.get(packageName); + if (multiDri == null) { consolidated.put(packageName, info); + } else if (multiDri instanceof MultiDisplayResolveInfo) { + ((MultiDisplayResolveInfo) multiDri).addTarget(info); + } else { + // create consolidated target from the single DisplayResolveInfo + MultiDisplayResolveInfo multiDisplayResolveInfo = + new MultiDisplayResolveInfo(packageName, multiDri); + multiDisplayResolveInfo.addTarget(info); + consolidated.put(packageName, multiDisplayResolveInfo); } } mSortedList.addAll(consolidated.values()); diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java index e23a3cad914bd..cb84ff907069d 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java @@ -293,6 +293,60 @@ public class ChooserActivityTest { assertThat(chosen[0], is(toChoose)); } + @Test + public void fourOptionsStackedIntoOneTarget() throws InterruptedException { + Intent sendIntent = createSendTextIntent(); + + // create 12 unique app targets to ensure the app ranking row can be filled, otherwise + // targets will not stack + List resolvedComponentInfos = createResolvedComponentsForTest(12); + + // next create 4 targets in a single app that should be stacked into a single target + String packageName = "xxx.yyy"; + String appName = "aaa"; + ComponentName cn = new ComponentName(packageName, appName); + Intent intent = new Intent("fakeIntent"); + List infosToStack = new ArrayList<>(); + for (int i = 0; i < 4; i++) { + ResolveInfo resolveInfo = ResolverDataProvider.createResolveInfo(i, + UserHandle.USER_CURRENT); + resolveInfo.activityInfo.applicationInfo.name = appName; + resolveInfo.activityInfo.applicationInfo.packageName = packageName; + resolveInfo.activityInfo.packageName = packageName; + resolveInfo.activityInfo.name = "ccc" + i; + infosToStack.add(new ResolvedComponentInfo(cn, intent, resolveInfo)); + } + resolvedComponentInfos.addAll(infosToStack); + + when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(), + Mockito.anyBoolean(), + Mockito.isA(List.class))).thenReturn(resolvedComponentInfos); + + final ChooserWrapperActivity activity = mActivityRule + .launchActivity(Intent.createChooser(sendIntent, null)); + waitForIdle(); + + // expect 12 unique targets + 1 group + 4 ranked app targets + assertThat(activity.getAdapter().getCount(), is(17)); + + ResolveInfo[] chosen = new ResolveInfo[1]; + sOverrides.onSafelyStartCallback = targetInfo -> { + chosen[0] = targetInfo.getResolveInfo(); + return true; + }; + + onView(withText(appName)).perform(click()); + waitForIdle(); + + // clicking will launch a dialog to choose the activity within the app + onView(withText(appName)).check(matches(isDisplayed())); + int i = 0; + for (ResolvedComponentInfo rci: infosToStack) { + onView(withText("ccc" + i)).check(matches(isDisplayed())); + ++i; + } + } + @Test public void updateChooserCountsAndModelAfterUserSelection() throws InterruptedException { Intent sendIntent = createSendTextIntent();