• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.intentresolver;
18 
19 import static android.app.Activity.RESULT_OK;
20 
21 import static androidx.test.espresso.Espresso.onView;
22 import static androidx.test.espresso.action.ViewActions.click;
23 import static androidx.test.espresso.action.ViewActions.longClick;
24 import static androidx.test.espresso.action.ViewActions.swipeUp;
25 import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
26 import static androidx.test.espresso.assertion.ViewAssertions.matches;
27 import static androidx.test.espresso.matcher.ViewMatchers.hasSibling;
28 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
29 import static androidx.test.espresso.matcher.ViewMatchers.withId;
30 import static androidx.test.espresso.matcher.ViewMatchers.withText;
31 
32 import static com.android.intentresolver.ChooserActivity.TARGET_TYPE_CHOOSER_TARGET;
33 import static com.android.intentresolver.ChooserActivity.TARGET_TYPE_DEFAULT;
34 import static com.android.intentresolver.ChooserActivity.TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE;
35 import static com.android.intentresolver.ChooserActivity.TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER;
36 import static com.android.intentresolver.ChooserListAdapter.CALLER_TARGET_SCORE_BOOST;
37 import static com.android.intentresolver.ChooserListAdapter.SHORTCUT_TARGET_SCORE_BOOST;
38 import static com.android.intentresolver.MatcherUtils.first;
39 
40 import static com.google.common.truth.Truth.assertThat;
41 
42 import static junit.framework.Assert.assertNull;
43 
44 import static org.hamcrest.CoreMatchers.allOf;
45 import static org.hamcrest.CoreMatchers.is;
46 import static org.hamcrest.CoreMatchers.not;
47 import static org.hamcrest.MatcherAssert.assertThat;
48 import static org.junit.Assert.assertEquals;
49 import static org.mockito.ArgumentMatchers.any;
50 import static org.mockito.ArgumentMatchers.anyBoolean;
51 import static org.mockito.ArgumentMatchers.anyInt;
52 import static org.mockito.ArgumentMatchers.anyLong;
53 import static org.mockito.ArgumentMatchers.eq;
54 import static org.mockito.Mockito.mock;
55 import static org.mockito.Mockito.times;
56 import static org.mockito.Mockito.verify;
57 import static org.mockito.Mockito.when;
58 
59 import android.app.PendingIntent;
60 import android.app.usage.UsageStatsManager;
61 import android.content.BroadcastReceiver;
62 import android.content.ClipData;
63 import android.content.ClipDescription;
64 import android.content.ClipboardManager;
65 import android.content.ComponentName;
66 import android.content.Context;
67 import android.content.Intent;
68 import android.content.IntentFilter;
69 import android.content.pm.ActivityInfo;
70 import android.content.pm.ApplicationInfo;
71 import android.content.pm.PackageManager;
72 import android.content.pm.ResolveInfo;
73 import android.content.pm.ShortcutInfo;
74 import android.content.pm.ShortcutManager.ShareShortcutInfo;
75 import android.content.res.Configuration;
76 import android.content.res.Resources;
77 import android.database.Cursor;
78 import android.graphics.Bitmap;
79 import android.graphics.Canvas;
80 import android.graphics.Color;
81 import android.graphics.Paint;
82 import android.graphics.drawable.Icon;
83 import android.net.Uri;
84 import android.os.Bundle;
85 import android.os.UserHandle;
86 import android.provider.DeviceConfig;
87 import android.service.chooser.ChooserAction;
88 import android.service.chooser.ChooserTarget;
89 import android.util.HashedStringCache;
90 import android.util.Pair;
91 import android.util.SparseArray;
92 import android.view.View;
93 import android.view.ViewGroup;
94 
95 import androidx.annotation.CallSuper;
96 import androidx.annotation.NonNull;
97 import androidx.recyclerview.widget.GridLayoutManager;
98 import androidx.recyclerview.widget.RecyclerView;
99 import androidx.test.espresso.contrib.RecyclerViewActions;
100 import androidx.test.espresso.matcher.BoundedDiagnosingMatcher;
101 import androidx.test.platform.app.InstrumentationRegistry;
102 import androidx.test.rule.ActivityTestRule;
103 
104 import com.android.intentresolver.chooser.DisplayResolveInfo;
105 import com.android.intentresolver.flags.Flags;
106 import com.android.intentresolver.shortcuts.ShortcutLoader;
107 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
108 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
109 import com.android.systemui.flags.BooleanFlag;
110 
111 import org.hamcrest.Description;
112 import org.hamcrest.Matcher;
113 import org.hamcrest.Matchers;
114 import org.junit.Before;
115 import org.junit.Ignore;
116 import org.junit.Rule;
117 import org.junit.Test;
118 import org.junit.rules.RuleChain;
119 import org.junit.rules.TestRule;
120 import org.junit.runner.RunWith;
121 import org.junit.runners.Parameterized;
122 import org.mockito.ArgumentCaptor;
123 import org.mockito.Mockito;
124 
125 import java.util.ArrayList;
126 import java.util.Arrays;
127 import java.util.Collection;
128 import java.util.HashMap;
129 import java.util.List;
130 import java.util.Map;
131 import java.util.concurrent.CountDownLatch;
132 import java.util.concurrent.atomic.AtomicReference;
133 import java.util.function.Consumer;
134 import java.util.function.Function;
135 
136 /**
137  * Instrumentation tests for the IntentResolver module's Sharesheet (ChooserActivity).
138  * TODO: remove methods that supported running these tests against arbitrary ChooserActivity
139  * subclasses. Those were left over from an earlier version where IntentResolver's ChooserActivity
140  * inherited from the framework version at com.android.internal.app.ChooserActivity, and this test
141  * file inherited from the framework's version as well. Once the migration to the IntentResolver
142  * package is complete, that aspect of the test design can revert to match the style of the
143  * framework tests prior to ag/16482932.
144  * TODO: this can simply be renamed to "ChooserActivityTest" if that's ever unambiguous (i.e., if
145  * there's no risk of confusion with the framework tests that currently share the same name).
146  */
147 @RunWith(Parameterized.class)
148 public class UnbundledChooserActivityTest {
149 
150     /* --------
151      * Subclasses should copy the following section verbatim (or alternatively could specify some
152      * additional @Parameterized.Parameters, as long as the correct parameters are used to
153      * initialize the ChooserActivityTest). The subclasses should also be @RunWith the
154      * `Parameterized` runner.
155      * --------
156      */
157 
158     private static final Function<PackageManager, PackageManager> DEFAULT_PM = pm -> pm;
159     private static final Function<PackageManager, PackageManager> NO_APP_PREDICTION_SERVICE_PM =
160             pm -> {
161                 PackageManager mock = Mockito.spy(pm);
162                 when(mock.getAppPredictionServicePackageName()).thenReturn(null);
163                 return mock;
164             };
165 
166     private static final List<BooleanFlag> ALL_FLAGS =
167             Arrays.asList(
168                     Flags.SHARESHEET_CUSTOM_ACTIONS,
169                     Flags.SHARESHEET_RESELECTION_ACTION,
170                     Flags.SHARESHEET_IMAGE_AND_TEXT_PREVIEW,
171                     Flags.SHARESHEET_SCROLLABLE_IMAGE_PREVIEW);
172 
173     private static final Map<BooleanFlag, Boolean> ALL_FLAGS_OFF =
174             createAllFlagsOverride(false);
175     private static final Map<BooleanFlag, Boolean> ALL_FLAGS_ON =
176             createAllFlagsOverride(true);
177 
178     @Parameterized.Parameters
packageManagers()179     public static Collection packageManagers() {
180         return Arrays.asList(new Object[][] {
181                 // Default PackageManager and all flags off
182                 { DEFAULT_PM, ALL_FLAGS_OFF },
183                 // Default PackageManager and all flags on
184                 { DEFAULT_PM, ALL_FLAGS_ON },
185                 // No App Prediction Service and all flags off
186                 { NO_APP_PREDICTION_SERVICE_PM, ALL_FLAGS_OFF },
187                 // No App Prediction Service and all flags on
188                 { NO_APP_PREDICTION_SERVICE_PM, ALL_FLAGS_ON }
189         });
190     }
191 
createAllFlagsOverride(boolean value)192     private static Map<BooleanFlag, Boolean> createAllFlagsOverride(boolean value) {
193         HashMap<BooleanFlag, Boolean> overrides = new HashMap<>(ALL_FLAGS.size());
194         for (BooleanFlag flag : ALL_FLAGS) {
195             overrides.put(flag, value);
196         }
197         return overrides;
198     }
199 
200     /* --------
201      * Subclasses can override the following methods to customize test behavior.
202      * --------
203      */
204 
205     /**
206      * Perform any necessary per-test initialization steps (subclasses may add additional steps
207      * before and/or after calling up to the superclass implementation).
208      */
209     @CallSuper
setup()210     protected void setup() {
211         // TODO: use the other form of `adoptShellPermissionIdentity()` where we explicitly list the
212         // permissions we require (which we'll read from the manifest at runtime).
213         InstrumentationRegistry
214                 .getInstrumentation()
215                 .getUiAutomation()
216                 .adoptShellPermissionIdentity();
217 
218         cleanOverrideData();
219         ChooserActivityOverrideData.getInstance().featureFlagRepository =
220                 new TestFeatureFlagRepository(mFlags);
221     }
222 
223     /**
224      * Given an intent that was constructed in a test, perform any additional configuration to
225      * specify the appropriate concrete ChooserActivity subclass. The activity launched by this
226      * intent must descend from android.intentresolver.ChooserActivity (for our ActivityTestRule), and
227      * must also implement the android.intentresolver.IChooserWrapper interface (since test code will
228      * assume the ability to make unsafe downcasts).
229      */
getConcreteIntentForLaunch(Intent clientIntent)230     protected Intent getConcreteIntentForLaunch(Intent clientIntent) {
231         clientIntent.setClass(
232                 InstrumentationRegistry.getInstrumentation().getTargetContext(),
233                 com.android.intentresolver.ChooserWrapperActivity.class);
234         return clientIntent;
235     }
236 
237     /**
238      * Whether {@code #testIsAppPredictionServiceAvailable} should verify the behavior after
239      * changing the availability conditions at runtime. In the unbundled chooser, the availability
240      * is cached at start and will never be re-evaluated.
241      * TODO: remove when we no longer want to test the system's on-the-fly evaluation.
242      */
shouldTestTogglingAppPredictionServiceAvailabilityAtRuntime()243     protected boolean shouldTestTogglingAppPredictionServiceAvailabilityAtRuntime() {
244         return false;
245     }
246 
247     /* --------
248      * The code in this section is unorthodox and can be simplified/reverted when we no longer need
249      * to support the parallel chooser implementations.
250      * --------
251      */
252 
253     @Rule
254     public final TestRule mRule;
255 
256     // Shared test code references the activity under test as ChooserActivity, the common ancestor
257     // of any (inheritance-based) chooser implementation. For testing purposes, that activity will
258     // usually be cast to IChooserWrapper to expose instrumentation.
259     private ActivityTestRule<ChooserActivity> mActivityRule =
260             new ActivityTestRule<>(ChooserActivity.class, false, false) {
261                 @Override
262                 public ChooserActivity launchActivity(Intent clientIntent) {
263                     return super.launchActivity(getConcreteIntentForLaunch(clientIntent));
264                 }
265             };
266 
267     @Before
doPolymorphicSetup()268     public final void doPolymorphicSetup() {
269         // The base class needs a @Before-annotated setup for when it runs against the system
270         // chooser, while subclasses need to be able to specify their own setup behavior. Notably
271         // the unbundled chooser, running in user-space, needs to take additional steps before it
272         // can run #cleanOverrideData() (which writes to DeviceConfig).
273         setup();
274     }
275 
276     /* --------
277      * Subclasses can ignore the remaining code and inherit the full suite of tests.
278      * --------
279      */
280 
281     private static final String TEST_MIME_TYPE = "application/TestType";
282 
283     private static final int CONTENT_PREVIEW_IMAGE = 1;
284     private static final int CONTENT_PREVIEW_FILE = 2;
285     private static final int CONTENT_PREVIEW_TEXT = 3;
286 
287     private final Function<PackageManager, PackageManager> mPackageManagerOverride;
288     private final Map<BooleanFlag, Boolean> mFlags;
289 
290 
UnbundledChooserActivityTest( Function<PackageManager, PackageManager> packageManagerOverride, Map<BooleanFlag, Boolean> flags)291     public UnbundledChooserActivityTest(
292                 Function<PackageManager, PackageManager> packageManagerOverride,
293                 Map<BooleanFlag, Boolean> flags) {
294         mPackageManagerOverride = packageManagerOverride;
295         mFlags = flags;
296 
297         mRule = RuleChain
298                 .outerRule(new FeatureFlagRule(flags))
299                 .around(mActivityRule);
300     }
301 
setDeviceConfigProperty( @onNull String propertyName, @NonNull String value)302     private void setDeviceConfigProperty(
303             @NonNull String propertyName,
304             @NonNull String value) {
305         // TODO: consider running with {@link #runWithShellPermissionIdentity()} to more narrowly
306         // request WRITE_DEVICE_CONFIG permissions if we get rid of the broad grant we currently
307         // configure in {@link #setup()}.
308         // TODO: is it really appropriate that this is always set with makeDefault=true?
309         boolean valueWasSet = DeviceConfig.setProperty(
310                 DeviceConfig.NAMESPACE_SYSTEMUI,
311                 propertyName,
312                 value,
313                 true /* makeDefault */);
314         if (!valueWasSet) {
315             throw new IllegalStateException(
316                         "Could not set " + propertyName + " to " + value);
317         }
318     }
319 
cleanOverrideData()320     public void cleanOverrideData() {
321         ChooserActivityOverrideData.getInstance().reset();
322         ChooserActivityOverrideData.getInstance().createPackageManager = mPackageManagerOverride;
323 
324         setDeviceConfigProperty(
325                 SystemUiDeviceConfigFlags.APPLY_SHARING_APP_LIMITS_IN_SYSUI,
326                 Boolean.toString(true));
327     }
328 
329     @Test
customTitle()330     public void customTitle() throws InterruptedException {
331         Intent viewIntent = createViewTextIntent();
332         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
333 
334         setupResolverControllers(resolvedComponentInfos);
335         final IChooserWrapper activity = (IChooserWrapper) mActivityRule.launchActivity(
336                 Intent.createChooser(viewIntent, "chooser test"));
337 
338         waitForIdle();
339         assertThat(activity.getAdapter().getCount(), is(2));
340         assertThat(activity.getAdapter().getServiceTargetCount(), is(0));
341         onView(withId(android.R.id.title)).check(matches(withText("chooser test")));
342     }
343 
344     @Test
customTitleIgnoredForSendIntents()345     public void customTitleIgnoredForSendIntents() throws InterruptedException {
346         Intent sendIntent = createSendTextIntent();
347         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
348 
349         setupResolverControllers(resolvedComponentInfos);
350         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "chooser test"));
351         waitForIdle();
352         onView(withId(android.R.id.title))
353                 .check(matches(withText(com.android.internal.R.string.whichSendApplication)));
354     }
355 
356     @Test
emptyTitle()357     public void emptyTitle() throws InterruptedException {
358         Intent sendIntent = createSendTextIntent();
359         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
360 
361         setupResolverControllers(resolvedComponentInfos);
362         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
363         waitForIdle();
364         onView(withId(android.R.id.title))
365                 .check(matches(withText(com.android.internal.R.string.whichSendApplication)));
366     }
367 
368     @Test
emptyPreviewTitleAndThumbnail()369     public void emptyPreviewTitleAndThumbnail() throws InterruptedException {
370         Intent sendIntent = createSendTextIntentWithPreview(null, null);
371         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
372 
373         setupResolverControllers(resolvedComponentInfos);
374         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
375         waitForIdle();
376         onView(withId(com.android.internal.R.id.content_preview_title))
377                 .check(matches(not(isDisplayed())));
378         onView(withId(com.android.internal.R.id.content_preview_thumbnail))
379                 .check(matches(not(isDisplayed())));
380     }
381 
382     @Test
visiblePreviewTitleWithoutThumbnail()383     public void visiblePreviewTitleWithoutThumbnail() throws InterruptedException {
384         String previewTitle = "My Content Preview Title";
385         Intent sendIntent = createSendTextIntentWithPreview(previewTitle, null);
386         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
387 
388         setupResolverControllers(resolvedComponentInfos);
389         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
390         waitForIdle();
391         onView(withId(com.android.internal.R.id.content_preview_title))
392                 .check(matches(isDisplayed()));
393         onView(withId(com.android.internal.R.id.content_preview_title))
394                 .check(matches(withText(previewTitle)));
395         onView(withId(com.android.internal.R.id.content_preview_thumbnail))
396                 .check(matches(not(isDisplayed())));
397     }
398 
399     @Test
visiblePreviewTitleWithInvalidThumbnail()400     public void visiblePreviewTitleWithInvalidThumbnail() throws InterruptedException {
401         String previewTitle = "My Content Preview Title";
402         Intent sendIntent = createSendTextIntentWithPreview(previewTitle,
403                 Uri.parse("tel:(+49)12345789"));
404         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
405 
406         setupResolverControllers(resolvedComponentInfos);
407         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
408         waitForIdle();
409         onView(withId(com.android.internal.R.id.content_preview_title))
410                 .check(matches(isDisplayed()));
411         onView(withId(com.android.internal.R.id.content_preview_thumbnail))
412                 .check(matches(not(isDisplayed())));
413     }
414 
415     @Test
visiblePreviewTitleAndThumbnail()416     public void visiblePreviewTitleAndThumbnail() throws InterruptedException {
417         String previewTitle = "My Content Preview Title";
418         Intent sendIntent = createSendTextIntentWithPreview(previewTitle,
419                 Uri.parse("android.resource://com.android.frameworks.coretests/"
420                         + R.drawable.test320x240));
421         ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
422         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
423 
424         setupResolverControllers(resolvedComponentInfos);
425         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
426         waitForIdle();
427         onView(withId(com.android.internal.R.id.content_preview_title))
428                 .check(matches(isDisplayed()));
429         onView(withId(com.android.internal.R.id.content_preview_thumbnail))
430                 .check(matches(isDisplayed()));
431     }
432 
433     @Test @Ignore
twoOptionsAndUserSelectsOne()434     public void twoOptionsAndUserSelectsOne() throws InterruptedException {
435         Intent sendIntent = createSendTextIntent();
436         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
437 
438         setupResolverControllers(resolvedComponentInfos);
439 
440         final IChooserWrapper activity = (IChooserWrapper)
441                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
442         waitForIdle();
443 
444         assertThat(activity.getAdapter().getCount(), is(2));
445         onView(withId(com.android.internal.R.id.profile_button)).check(doesNotExist());
446 
447         ResolveInfo[] chosen = new ResolveInfo[1];
448         ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
449             chosen[0] = targetInfo.getResolveInfo();
450             return true;
451         };
452 
453         ResolveInfo toChoose = resolvedComponentInfos.get(0).getResolveInfoAt(0);
454         onView(withText(toChoose.activityInfo.name))
455                 .perform(click());
456         waitForIdle();
457         assertThat(chosen[0], is(toChoose));
458     }
459 
460     @Test @Ignore
fourOptionsStackedIntoOneTarget()461     public void fourOptionsStackedIntoOneTarget() throws InterruptedException {
462         Intent sendIntent = createSendTextIntent();
463 
464         // create just enough targets to ensure the a-z list should be shown
465         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(1);
466 
467         // next create 4 targets in a single app that should be stacked into a single target
468         String packageName = "xxx.yyy";
469         String appName = "aaa";
470         ComponentName cn = new ComponentName(packageName, appName);
471         Intent intent = new Intent("fakeIntent");
472         List<ResolvedComponentInfo> infosToStack = new ArrayList<>();
473         for (int i = 0; i < 4; i++) {
474             ResolveInfo resolveInfo = ResolverDataProvider.createResolveInfo(i,
475                     UserHandle.USER_CURRENT);
476             resolveInfo.activityInfo.applicationInfo.name = appName;
477             resolveInfo.activityInfo.applicationInfo.packageName = packageName;
478             resolveInfo.activityInfo.packageName = packageName;
479             resolveInfo.activityInfo.name = "ccc" + i;
480             infosToStack.add(new ResolvedComponentInfo(cn, intent, resolveInfo));
481         }
482         resolvedComponentInfos.addAll(infosToStack);
483 
484         setupResolverControllers(resolvedComponentInfos);
485 
486         final IChooserWrapper activity = (IChooserWrapper)
487                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
488         waitForIdle();
489 
490         // expect 1 unique targets + 1 group + 4 ranked app targets
491         assertThat(activity.getAdapter().getCount(), is(6));
492 
493         ResolveInfo[] chosen = new ResolveInfo[1];
494         ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
495             chosen[0] = targetInfo.getResolveInfo();
496             return true;
497         };
498 
499         onView(allOf(withText(appName), hasSibling(withText("")))).perform(click());
500         waitForIdle();
501 
502         // clicking will launch a dialog to choose the activity within the app
503         onView(withText(appName)).check(matches(isDisplayed()));
504         int i = 0;
505         for (ResolvedComponentInfo rci: infosToStack) {
506             onView(withText("ccc" + i)).check(matches(isDisplayed()));
507             ++i;
508         }
509     }
510 
511     @Test @Ignore
updateChooserCountsAndModelAfterUserSelection()512     public void updateChooserCountsAndModelAfterUserSelection() throws InterruptedException {
513         Intent sendIntent = createSendTextIntent();
514         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
515 
516         setupResolverControllers(resolvedComponentInfos);
517 
518         final IChooserWrapper activity = (IChooserWrapper)
519                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
520         waitForIdle();
521         UsageStatsManager usm = activity.getUsageStatsManager();
522         verify(ChooserActivityOverrideData.getInstance().resolverListController, times(1))
523                 .topK(any(List.class), anyInt());
524         assertThat(activity.getIsSelected(), is(false));
525         ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
526             return true;
527         };
528         ResolveInfo toChoose = resolvedComponentInfos.get(0).getResolveInfoAt(0);
529         onView(withText(toChoose.activityInfo.name))
530                 .perform(click());
531         waitForIdle();
532         verify(ChooserActivityOverrideData.getInstance().resolverListController, times(1))
533                 .updateChooserCounts(Mockito.anyString(), anyInt(), Mockito.anyString());
534         verify(ChooserActivityOverrideData.getInstance().resolverListController, times(1))
535                 .updateModel(toChoose.activityInfo.getComponentName());
536         assertThat(activity.getIsSelected(), is(true));
537     }
538 
539     @Ignore // b/148158199
540     @Test
noResultsFromPackageManager()541     public void noResultsFromPackageManager() {
542         setupResolverControllers(null);
543         Intent sendIntent = createSendTextIntent();
544         final ChooserActivity activity =
545                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
546         final IChooserWrapper wrapper = (IChooserWrapper) activity;
547 
548         waitForIdle();
549         assertThat(activity.isFinishing(), is(false));
550 
551         onView(withId(android.R.id.empty)).check(matches(isDisplayed()));
552         onView(withId(com.android.internal.R.id.profile_pager)).check(matches(not(isDisplayed())));
553         InstrumentationRegistry.getInstrumentation().runOnMainSync(
554                 () -> wrapper.getAdapter().handlePackagesChanged()
555         );
556         // backward compatibility. looks like we finish when data is empty after package change
557         assertThat(activity.isFinishing(), is(true));
558     }
559 
560     @Test
autoLaunchSingleResult()561     public void autoLaunchSingleResult() throws InterruptedException {
562         ResolveInfo[] chosen = new ResolveInfo[1];
563         ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
564             chosen[0] = targetInfo.getResolveInfo();
565             return true;
566         };
567 
568         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(1);
569         setupResolverControllers(resolvedComponentInfos);
570 
571         Intent sendIntent = createSendTextIntent();
572         final ChooserActivity activity =
573                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
574         waitForIdle();
575 
576         assertThat(chosen[0], is(resolvedComponentInfos.get(0).getResolveInfoAt(0)));
577         assertThat(activity.isFinishing(), is(true));
578     }
579 
580     @Test @Ignore
hasOtherProfileOneOption()581     public void hasOtherProfileOneOption() {
582         List<ResolvedComponentInfo> personalResolvedComponentInfos =
583                 createResolvedComponentsForTestWithOtherProfile(2, /* userId */ 10);
584         List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4);
585         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
586         markWorkProfileUserAvailable();
587 
588         ResolveInfo toChoose = personalResolvedComponentInfos.get(1).getResolveInfoAt(0);
589         Intent sendIntent = createSendTextIntent();
590         final IChooserWrapper activity = (IChooserWrapper)
591                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
592         waitForIdle();
593 
594         // The other entry is filtered to the other profile slot
595         assertThat(activity.getAdapter().getCount(), is(1));
596 
597         ResolveInfo[] chosen = new ResolveInfo[1];
598         ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
599             chosen[0] = targetInfo.getResolveInfo();
600             return true;
601         };
602 
603         // Make a stable copy of the components as the original list may be modified
604         List<ResolvedComponentInfo> stableCopy =
605                 createResolvedComponentsForTestWithOtherProfile(2, /* userId= */ 10);
606         waitForIdle();
607 
608         onView(first(withText(stableCopy.get(1).getResolveInfoAt(0).activityInfo.name)))
609                 .perform(click());
610         waitForIdle();
611         assertThat(chosen[0], is(toChoose));
612     }
613 
614     @Test @Ignore
hasOtherProfileTwoOptionsAndUserSelectsOne()615     public void hasOtherProfileTwoOptionsAndUserSelectsOne() throws Exception {
616         Intent sendIntent = createSendTextIntent();
617         List<ResolvedComponentInfo> resolvedComponentInfos =
618                 createResolvedComponentsForTestWithOtherProfile(3);
619         ResolveInfo toChoose = resolvedComponentInfos.get(1).getResolveInfoAt(0);
620 
621         setupResolverControllers(resolvedComponentInfos);
622         when(ChooserActivityOverrideData.getInstance().resolverListController.getLastChosen())
623                 .thenReturn(resolvedComponentInfos.get(0).getResolveInfoAt(0));
624 
625         final IChooserWrapper activity = (IChooserWrapper)
626                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
627         waitForIdle();
628 
629         // The other entry is filtered to the other profile slot
630         assertThat(activity.getAdapter().getCount(), is(2));
631 
632         ResolveInfo[] chosen = new ResolveInfo[1];
633         ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
634             chosen[0] = targetInfo.getResolveInfo();
635             return true;
636         };
637 
638         // Make a stable copy of the components as the original list may be modified
639         List<ResolvedComponentInfo> stableCopy =
640                 createResolvedComponentsForTestWithOtherProfile(3);
641         onView(withText(stableCopy.get(1).getResolveInfoAt(0).activityInfo.name))
642                 .perform(click());
643         waitForIdle();
644         assertThat(chosen[0], is(toChoose));
645     }
646 
647     @Test @Ignore
hasLastChosenActivityAndOtherProfile()648     public void hasLastChosenActivityAndOtherProfile() throws Exception {
649         Intent sendIntent = createSendTextIntent();
650         List<ResolvedComponentInfo> resolvedComponentInfos =
651                 createResolvedComponentsForTestWithOtherProfile(3);
652         ResolveInfo toChoose = resolvedComponentInfos.get(1).getResolveInfoAt(0);
653 
654         setupResolverControllers(resolvedComponentInfos);
655 
656         final IChooserWrapper activity = (IChooserWrapper)
657                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
658         waitForIdle();
659 
660         // The other entry is filtered to the last used slot
661         assertThat(activity.getAdapter().getCount(), is(2));
662 
663         ResolveInfo[] chosen = new ResolveInfo[1];
664         ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
665             chosen[0] = targetInfo.getResolveInfo();
666             return true;
667         };
668 
669         // Make a stable copy of the components as the original list may be modified
670         List<ResolvedComponentInfo> stableCopy =
671                 createResolvedComponentsForTestWithOtherProfile(3);
672         onView(withText(stableCopy.get(1).getResolveInfoAt(0).activityInfo.name))
673                 .perform(click());
674         waitForIdle();
675         assertThat(chosen[0], is(toChoose));
676     }
677 
678     @Test
679     @RequireFeatureFlags(
680             flags = { Flags.SHARESHEET_IMAGE_AND_TEXT_PREVIEW_NAME },
681             values = { true })
testImagePlusTextSharing_ExcludeText()682     public void testImagePlusTextSharing_ExcludeText() {
683         Intent sendIntent = createSendImageIntent(
684                 Uri.parse("android.resource://com.android.frameworks.coretests/"
685                         + R.drawable.test320x240));
686         ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
687         ChooserActivityOverrideData.getInstance().isImageType = true;
688         sendIntent.putExtra(Intent.EXTRA_TEXT, "https://google.com/search?q=google");
689 
690         List<ResolvedComponentInfo> resolvedComponentInfos = Arrays.asList(
691                 ResolverDataProvider.createResolvedComponentInfo(
692                         new ComponentName("org.imageviewer", "ImageTarget"),
693                         sendIntent),
694                 ResolverDataProvider.createResolvedComponentInfo(
695                         new ComponentName("org.textviewer", "UriTarget"),
696                         new Intent("VIEW_TEXT"))
697         );
698 
699         setupResolverControllers(resolvedComponentInfos);
700 
701         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
702         waitForIdle();
703 
704         onView(withId(R.id.include_text_action))
705                 .check(matches(isDisplayed()))
706                 .perform(click());
707         waitForIdle();
708 
709         AtomicReference<Intent> launchedIntentRef = new AtomicReference<>();
710         ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
711             launchedIntentRef.set(targetInfo.getTargetIntent());
712             return true;
713         };
714 
715         onView(withText(resolvedComponentInfos.get(0).getResolveInfoAt(0).activityInfo.name))
716                 .perform(click());
717         waitForIdle();
718         assertThat(launchedIntentRef.get().hasExtra(Intent.EXTRA_TEXT)).isFalse();
719     }
720 
721     @Test
722     @RequireFeatureFlags(
723             flags = { Flags.SHARESHEET_IMAGE_AND_TEXT_PREVIEW_NAME },
724             values = { true })
testImagePlusTextSharing_RemoveAndAddBackText()725     public void testImagePlusTextSharing_RemoveAndAddBackText() {
726         Intent sendIntent = createSendImageIntent(
727                 Uri.parse("android.resource://com.android.frameworks.coretests/"
728                         + R.drawable.test320x240));
729         ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
730         ChooserActivityOverrideData.getInstance().isImageType = true;
731         final String text = "https://google.com/search?q=google";
732         sendIntent.putExtra(Intent.EXTRA_TEXT, text);
733 
734         List<ResolvedComponentInfo> resolvedComponentInfos = Arrays.asList(
735                 ResolverDataProvider.createResolvedComponentInfo(
736                         new ComponentName("org.imageviewer", "ImageTarget"),
737                         sendIntent),
738                 ResolverDataProvider.createResolvedComponentInfo(
739                         new ComponentName("org.textviewer", "UriTarget"),
740                         new Intent("VIEW_TEXT"))
741         );
742 
743         setupResolverControllers(resolvedComponentInfos);
744 
745         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
746         waitForIdle();
747 
748         onView(withId(R.id.include_text_action))
749                 .check(matches(isDisplayed()))
750                 .perform(click());
751         waitForIdle();
752         onView(withId(R.id.include_text_action))
753                 .perform(click());
754         waitForIdle();
755 
756         AtomicReference<Intent> launchedIntentRef = new AtomicReference<>();
757         ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
758             launchedIntentRef.set(targetInfo.getTargetIntent());
759             return true;
760         };
761 
762         onView(withText(resolvedComponentInfos.get(0).getResolveInfoAt(0).activityInfo.name))
763                 .perform(click());
764         waitForIdle();
765         assertThat(launchedIntentRef.get().getStringExtra(Intent.EXTRA_TEXT)).isEqualTo(text);
766     }
767 
768     @Test
769     @RequireFeatureFlags(
770             flags = { Flags.SHARESHEET_IMAGE_AND_TEXT_PREVIEW_NAME },
771             values = { true })
testImagePlusTextSharing_TextExclusionDoesNotAffectAlternativeIntent()772     public void testImagePlusTextSharing_TextExclusionDoesNotAffectAlternativeIntent() {
773         Intent sendIntent = createSendImageIntent(
774                 Uri.parse("android.resource://com.android.frameworks.coretests/"
775                         + R.drawable.test320x240));
776         ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
777         ChooserActivityOverrideData.getInstance().isImageType = true;
778         sendIntent.putExtra(Intent.EXTRA_TEXT, "https://google.com/search?q=google");
779 
780         Intent alternativeIntent = createSendTextIntent();
781         final String text = "alternative intent";
782         alternativeIntent.putExtra(Intent.EXTRA_TEXT, text);
783 
784         List<ResolvedComponentInfo> resolvedComponentInfos = Arrays.asList(
785                 ResolverDataProvider.createResolvedComponentInfo(
786                         new ComponentName("org.imageviewer", "ImageTarget"),
787                         sendIntent),
788                 ResolverDataProvider.createResolvedComponentInfo(
789                         new ComponentName("org.textviewer", "UriTarget"),
790                         alternativeIntent)
791         );
792 
793         setupResolverControllers(resolvedComponentInfos);
794 
795         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
796         waitForIdle();
797 
798         onView(withId(R.id.include_text_action))
799                 .check(matches(isDisplayed()))
800                 .perform(click());
801         waitForIdle();
802 
803         AtomicReference<Intent> launchedIntentRef = new AtomicReference<>();
804         ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
805             launchedIntentRef.set(targetInfo.getTargetIntent());
806             return true;
807         };
808 
809         onView(withText(resolvedComponentInfos.get(1).getResolveInfoAt(0).activityInfo.name))
810                 .perform(click());
811         waitForIdle();
812         assertThat(launchedIntentRef.get().getStringExtra(Intent.EXTRA_TEXT)).isEqualTo(text);
813     }
814 
815     @Test
copyTextToClipboard()816     public void copyTextToClipboard() throws Exception {
817         Intent sendIntent = createSendTextIntent();
818         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
819 
820         setupResolverControllers(resolvedComponentInfos);
821 
822         final ChooserActivity activity =
823                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
824         waitForIdle();
825 
826         onView(withId(com.android.internal.R.id.chooser_copy_button)).check(matches(isDisplayed()));
827         onView(withId(com.android.internal.R.id.chooser_copy_button)).perform(click());
828         ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(
829                 Context.CLIPBOARD_SERVICE);
830         ClipData clipData = clipboard.getPrimaryClip();
831         assertThat("testing intent sending", is(clipData.getItemAt(0).getText()));
832 
833         ClipDescription clipDescription = clipData.getDescription();
834         assertThat("text/plain", is(clipDescription.getMimeType(0)));
835 
836         assertEquals(mActivityRule.getActivityResult().getResultCode(), RESULT_OK);
837     }
838 
839     @Test
copyTextToClipboardLogging()840     public void copyTextToClipboardLogging() {
841         Intent sendIntent = createSendTextIntent();
842         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
843 
844         setupResolverControllers(resolvedComponentInfos);
845 
846         final IChooserWrapper activity = (IChooserWrapper)
847                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
848         waitForIdle();
849 
850         onView(withId(com.android.internal.R.id.chooser_copy_button)).check(matches(isDisplayed()));
851         onView(withId(com.android.internal.R.id.chooser_copy_button)).perform(click());
852 
853         ChooserActivityLogger logger = activity.getChooserActivityLogger();
854         verify(logger, times(1)).logActionSelected(eq(ChooserActivityLogger.SELECTION_TYPE_COPY));
855     }
856 
857     @Test
858     @Ignore
testNearbyShareLogging()859     public void testNearbyShareLogging() throws Exception {
860         Intent sendIntent = createSendTextIntent();
861         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
862 
863         setupResolverControllers(resolvedComponentInfos);
864 
865         final IChooserWrapper activity = (IChooserWrapper)
866                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
867         waitForIdle();
868 
869         onView(withId(com.android.internal.R.id.chooser_nearby_button))
870                 .check(matches(isDisplayed()));
871         onView(withId(com.android.internal.R.id.chooser_nearby_button)).perform(click());
872 
873         // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events.
874     }
875 
876 
877 
878     @Test @Ignore
testEditImageLogs()879     public void testEditImageLogs() throws Exception {
880         Intent sendIntent = createSendImageIntent(
881                 Uri.parse("android.resource://com.android.frameworks.coretests/"
882                         + R.drawable.test320x240));
883 
884         ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
885         ChooserActivityOverrideData.getInstance().isImageType = true;
886 
887         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
888 
889         setupResolverControllers(resolvedComponentInfos);
890 
891         final IChooserWrapper activity = (IChooserWrapper)
892                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
893         waitForIdle();
894 
895         onView(withId(com.android.internal.R.id.chooser_edit_button)).check(matches(isDisplayed()));
896         onView(withId(com.android.internal.R.id.chooser_edit_button)).perform(click());
897 
898         // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events.
899     }
900 
901 
902     @Test
oneVisibleImagePreview()903     public void oneVisibleImagePreview() {
904         Uri uri = Uri.parse("android.resource://com.android.frameworks.coretests/"
905                 + R.drawable.test320x240);
906 
907         ArrayList<Uri> uris = new ArrayList<>();
908         uris.add(uri);
909 
910         Intent sendIntent = createSendUriIntentWithPreview(uris);
911         ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
912         ChooserActivityOverrideData.getInstance().isImageType = true;
913 
914         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
915 
916         setupResolverControllers(resolvedComponentInfos);
917         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
918         waitForIdle();
919         onView(withId(com.android.internal.R.id.content_preview_image_area))
920                 .check((view, exception) -> {
921                     if (exception != null) {
922                         throw exception;
923                     }
924                     ViewGroup parent = (ViewGroup) view;
925                     ArrayList<View> visibleViews = new ArrayList<>();
926                     for (int i = 0, count = parent.getChildCount(); i < count; i++) {
927                         View child = parent.getChildAt(i);
928                         if (child.getVisibility() == View.VISIBLE) {
929                             visibleViews.add(child);
930                         }
931                     }
932                     assertThat(visibleViews.size(), is(1));
933                     assertThat(
934                             "image preview view is fully visible",
935                             isDisplayed().matches(visibleViews.get(0)));
936                 });
937     }
938 
939     @Test
940     @RequireFeatureFlags(
941             flags = { Flags.SHARESHEET_SCROLLABLE_IMAGE_PREVIEW_NAME },
942             values = { false })
twoVisibleImagePreview()943     public void twoVisibleImagePreview() {
944         Uri uri = Uri.parse("android.resource://com.android.frameworks.coretests/"
945                 + R.drawable.test320x240);
946 
947         ArrayList<Uri> uris = new ArrayList<>();
948         uris.add(uri);
949         uris.add(uri);
950 
951         Intent sendIntent = createSendUriIntentWithPreview(uris);
952         ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
953         ChooserActivityOverrideData.getInstance().isImageType = true;
954 
955         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
956 
957         setupResolverControllers(resolvedComponentInfos);
958         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
959         waitForIdle();
960         onView(withId(com.android.internal.R.id.content_preview_image_1_large))
961                 .check(matches(isDisplayed()));
962         onView(withId(com.android.internal.R.id.content_preview_image_2_large))
963                 .check(matches(isDisplayed()));
964         onView(withId(com.android.internal.R.id.content_preview_image_2_small))
965                 .check(matches(not(isDisplayed())));
966         onView(withId(com.android.internal.R.id.content_preview_image_3_small))
967                 .check(matches(not(isDisplayed())));
968     }
969 
970     @Test
971     @RequireFeatureFlags(
972             flags = { Flags.SHARESHEET_SCROLLABLE_IMAGE_PREVIEW_NAME },
973             values = { false })
threeOrMoreVisibleImagePreview()974     public void threeOrMoreVisibleImagePreview() {
975         Uri uri = Uri.parse("android.resource://com.android.frameworks.coretests/"
976                 + R.drawable.test320x240);
977 
978         ArrayList<Uri> uris = new ArrayList<>();
979         uris.add(uri);
980         uris.add(uri);
981         uris.add(uri);
982         uris.add(uri);
983         uris.add(uri);
984 
985         Intent sendIntent = createSendUriIntentWithPreview(uris);
986         ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
987         ChooserActivityOverrideData.getInstance().isImageType = true;
988 
989         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
990 
991         setupResolverControllers(resolvedComponentInfos);
992         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
993         waitForIdle();
994         onView(withId(com.android.internal.R.id.content_preview_image_1_large))
995                 .check(matches(isDisplayed()));
996         onView(withId(com.android.internal.R.id.content_preview_image_2_large))
997                 .check(matches(not(isDisplayed())));
998         onView(withId(com.android.internal.R.id.content_preview_image_2_small))
999                 .check(matches(isDisplayed()));
1000         onView(withId(com.android.internal.R.id.content_preview_image_3_small))
1001                 .check(matches(isDisplayed()));
1002     }
1003 
1004     @Test
1005     @RequireFeatureFlags(
1006             flags = { Flags.SHARESHEET_SCROLLABLE_IMAGE_PREVIEW_NAME },
1007             values = { true })
testManyVisibleImagePreview_ScrollableImagePreview()1008     public void testManyVisibleImagePreview_ScrollableImagePreview() {
1009         Uri uri = Uri.parse("android.resource://com.android.frameworks.coretests/"
1010                 + R.drawable.test320x240);
1011 
1012         ArrayList<Uri> uris = new ArrayList<>();
1013         uris.add(uri);
1014         uris.add(uri);
1015         uris.add(uri);
1016         uris.add(uri);
1017         uris.add(uri);
1018         uris.add(uri);
1019         uris.add(uri);
1020         uris.add(uri);
1021         uris.add(uri);
1022         uris.add(uri);
1023 
1024         Intent sendIntent = createSendUriIntentWithPreview(uris);
1025         ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
1026         ChooserActivityOverrideData.getInstance().isImageType = true;
1027 
1028         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1029 
1030         setupResolverControllers(resolvedComponentInfos);
1031         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1032         waitForIdle();
1033         onView(withId(com.android.internal.R.id.content_preview_image_area))
1034                 .perform(RecyclerViewActions.scrollToLastPosition())
1035                 .check((view, exception) -> {
1036                     if (exception != null) {
1037                         throw exception;
1038                     }
1039                     RecyclerView recyclerView = (RecyclerView) view;
1040                     assertThat(recyclerView.getAdapter().getItemCount(), is(uris.size()));
1041                 });
1042     }
1043 
1044     @Test
1045     @RequireFeatureFlags(
1046             flags = { Flags.SHARESHEET_IMAGE_AND_TEXT_PREVIEW_NAME },
1047             values = { true })
testImageAndTextPreview()1048     public void testImageAndTextPreview() {
1049         final Uri uri = Uri.parse("android.resource://com.android.frameworks.coretests/"
1050                 + R.drawable.test320x240);
1051         final String sharedText = "text-" + System.currentTimeMillis();
1052 
1053         ArrayList<Uri> uris = new ArrayList<>();
1054         uris.add(uri);
1055 
1056         Intent sendIntent = createSendUriIntentWithPreview(uris);
1057         sendIntent.putExtra(Intent.EXTRA_TEXT, sharedText);
1058         ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
1059         ChooserActivityOverrideData.getInstance().isImageType = true;
1060 
1061         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1062 
1063         setupResolverControllers(resolvedComponentInfos);
1064         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1065         waitForIdle();
1066         onView(withText(sharedText))
1067                 .check(matches(isDisplayed()));
1068     }
1069 
1070     @Test
testOnCreateLogging()1071     public void testOnCreateLogging() {
1072         Intent sendIntent = createSendTextIntent();
1073         sendIntent.setType(TEST_MIME_TYPE);
1074 
1075         final IChooserWrapper activity = (IChooserWrapper)
1076                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "logger test"));
1077         ChooserActivityLogger logger = activity.getChooserActivityLogger();
1078         waitForIdle();
1079 
1080         verify(logger).logChooserActivityShown(eq(false), eq(TEST_MIME_TYPE), anyLong());
1081     }
1082 
1083     @Test
testOnCreateLoggingFromWorkProfile()1084     public void testOnCreateLoggingFromWorkProfile() {
1085         Intent sendIntent = createSendTextIntent();
1086         sendIntent.setType(TEST_MIME_TYPE);
1087         ChooserActivityOverrideData.getInstance().alternateProfileSetting =
1088                 MetricsEvent.MANAGED_PROFILE;
1089 
1090         final IChooserWrapper activity = (IChooserWrapper)
1091                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "logger test"));
1092         ChooserActivityLogger logger = activity.getChooserActivityLogger();
1093         waitForIdle();
1094 
1095         verify(logger).logChooserActivityShown(eq(true), eq(TEST_MIME_TYPE), anyLong());
1096     }
1097 
1098     @Test
testEmptyPreviewLogging()1099     public void testEmptyPreviewLogging() {
1100         Intent sendIntent = createSendTextIntentWithPreview(null, null);
1101 
1102         final IChooserWrapper activity = (IChooserWrapper)
1103                 mActivityRule.launchActivity(
1104                         Intent.createChooser(sendIntent, "empty preview logger test"));
1105         ChooserActivityLogger logger = activity.getChooserActivityLogger();
1106         waitForIdle();
1107 
1108         verify(logger).logChooserActivityShown(eq(false), eq(null), anyLong());
1109     }
1110 
1111     @Test
testTitlePreviewLogging()1112     public void testTitlePreviewLogging() {
1113         Intent sendIntent = createSendTextIntentWithPreview("TestTitle", null);
1114 
1115         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1116 
1117         setupResolverControllers(resolvedComponentInfos);
1118 
1119         final IChooserWrapper activity = (IChooserWrapper)
1120                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1121         waitForIdle();
1122 
1123         // Second invocation is from onCreate
1124         ChooserActivityLogger logger = activity.getChooserActivityLogger();
1125         Mockito.verify(logger, times(1)).logActionShareWithPreview(eq(CONTENT_PREVIEW_TEXT));
1126     }
1127 
1128     @Test
testImagePreviewLogging()1129     public void testImagePreviewLogging() {
1130         Uri uri = Uri.parse("android.resource://com.android.frameworks.coretests/"
1131                 + R.drawable.test320x240);
1132 
1133         ArrayList<Uri> uris = new ArrayList<>();
1134         uris.add(uri);
1135 
1136         Intent sendIntent = createSendUriIntentWithPreview(uris);
1137         ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
1138         ChooserActivityOverrideData.getInstance().isImageType = true;
1139 
1140         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1141 
1142         setupResolverControllers(resolvedComponentInfos);
1143 
1144         final IChooserWrapper activity = (IChooserWrapper)
1145                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1146         waitForIdle();
1147         ChooserActivityLogger logger = activity.getChooserActivityLogger();
1148         Mockito.verify(logger, times(1)).logActionShareWithPreview(eq(CONTENT_PREVIEW_IMAGE));
1149     }
1150 
1151     @Test
oneVisibleFilePreview()1152     public void oneVisibleFilePreview() throws InterruptedException {
1153         Uri uri = Uri.parse("content://com.android.frameworks.coretests/app.pdf");
1154 
1155         ArrayList<Uri> uris = new ArrayList<>();
1156         uris.add(uri);
1157 
1158         Intent sendIntent = createSendUriIntentWithPreview(uris);
1159 
1160         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1161 
1162         setupResolverControllers(resolvedComponentInfos);
1163         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1164         waitForIdle();
1165         onView(withId(com.android.internal.R.id.content_preview_filename))
1166                 .check(matches(isDisplayed()));
1167         onView(withId(com.android.internal.R.id.content_preview_filename))
1168                 .check(matches(withText("app.pdf")));
1169         onView(withId(com.android.internal.R.id.content_preview_file_icon))
1170                 .check(matches(isDisplayed()));
1171     }
1172 
1173 
1174     @Test
moreThanOneVisibleFilePreview()1175     public void moreThanOneVisibleFilePreview() throws InterruptedException {
1176         Uri uri = Uri.parse("content://com.android.frameworks.coretests/app.pdf");
1177 
1178         ArrayList<Uri> uris = new ArrayList<>();
1179         uris.add(uri);
1180         uris.add(uri);
1181         uris.add(uri);
1182 
1183         Intent sendIntent = createSendUriIntentWithPreview(uris);
1184 
1185         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1186 
1187         setupResolverControllers(resolvedComponentInfos);
1188         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1189         waitForIdle();
1190         onView(withId(com.android.internal.R.id.content_preview_filename))
1191                 .check(matches(isDisplayed()));
1192         onView(withId(com.android.internal.R.id.content_preview_filename))
1193                 .check(matches(withText("app.pdf + 2 files")));
1194         onView(withId(com.android.internal.R.id.content_preview_file_icon))
1195                 .check(matches(isDisplayed()));
1196     }
1197 
1198     @Test
contentProviderThrowSecurityException()1199     public void contentProviderThrowSecurityException() throws InterruptedException {
1200         Uri uri = Uri.parse("content://com.android.frameworks.coretests/app.pdf");
1201 
1202         ArrayList<Uri> uris = new ArrayList<>();
1203         uris.add(uri);
1204 
1205         Intent sendIntent = createSendUriIntentWithPreview(uris);
1206 
1207         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1208         setupResolverControllers(resolvedComponentInfos);
1209 
1210         ChooserActivityOverrideData.getInstance().resolverForceException = true;
1211 
1212         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1213         waitForIdle();
1214         onView(withId(com.android.internal.R.id.content_preview_filename))
1215                 .check(matches(isDisplayed()));
1216         onView(withId(com.android.internal.R.id.content_preview_filename))
1217                 .check(matches(withText("app.pdf")));
1218         onView(withId(com.android.internal.R.id.content_preview_file_icon))
1219                 .check(matches(isDisplayed()));
1220     }
1221 
1222     @Test
contentProviderReturnsNoColumns()1223     public void contentProviderReturnsNoColumns() throws InterruptedException {
1224         Uri uri = Uri.parse("content://com.android.frameworks.coretests/app.pdf");
1225 
1226         ArrayList<Uri> uris = new ArrayList<>();
1227         uris.add(uri);
1228         uris.add(uri);
1229 
1230         Intent sendIntent = createSendUriIntentWithPreview(uris);
1231 
1232         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1233         setupResolverControllers(resolvedComponentInfos);
1234 
1235         Cursor cursor = mock(Cursor.class);
1236         when(cursor.getCount()).thenReturn(1);
1237         Mockito.doNothing().when(cursor).close();
1238         when(cursor.moveToFirst()).thenReturn(true);
1239         when(cursor.getColumnIndex(Mockito.anyString())).thenReturn(-1);
1240 
1241         ChooserActivityOverrideData.getInstance().resolverCursor = cursor;
1242 
1243         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1244         waitForIdle();
1245         onView(withId(com.android.internal.R.id.content_preview_filename))
1246                 .check(matches(isDisplayed()));
1247         onView(withId(com.android.internal.R.id.content_preview_filename))
1248                 .check(matches(withText("app.pdf + 1 file")));
1249         onView(withId(com.android.internal.R.id.content_preview_file_icon))
1250                 .check(matches(isDisplayed()));
1251     }
1252 
1253     @Test
testGetBaseScore()1254     public void testGetBaseScore() {
1255         final float testBaseScore = 0.89f;
1256 
1257         Intent sendIntent = createSendTextIntent();
1258         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1259 
1260         setupResolverControllers(resolvedComponentInfos);
1261 
1262         when(
1263                 ChooserActivityOverrideData
1264                         .getInstance()
1265                         .resolverListController
1266                         .getScore(Mockito.isA(DisplayResolveInfo.class)))
1267                 .thenReturn(testBaseScore);
1268 
1269         final IChooserWrapper activity = (IChooserWrapper)
1270                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1271         waitForIdle();
1272 
1273         final DisplayResolveInfo testDri =
1274                 activity.createTestDisplayResolveInfo(sendIntent,
1275                 ResolverDataProvider.createResolveInfo(3, 0), "testLabel", "testInfo", sendIntent,
1276                 /* resolveInfoPresentationGetter */ null);
1277         final ChooserListAdapter adapter = activity.getAdapter();
1278 
1279         assertThat(adapter.getBaseScore(null, 0), is(CALLER_TARGET_SCORE_BOOST));
1280         assertThat(adapter.getBaseScore(testDri, TARGET_TYPE_DEFAULT), is(testBaseScore));
1281         assertThat(adapter.getBaseScore(testDri, TARGET_TYPE_CHOOSER_TARGET), is(testBaseScore));
1282         assertThat(adapter.getBaseScore(testDri, TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE),
1283                 is(testBaseScore * SHORTCUT_TARGET_SCORE_BOOST));
1284         assertThat(adapter.getBaseScore(testDri, TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER),
1285                 is(testBaseScore * SHORTCUT_TARGET_SCORE_BOOST));
1286     }
1287 
1288     // This test is too long and too slow and should not be taken as an example for future tests.
1289     @Test
testDirectTargetSelectionLogging()1290     public void testDirectTargetSelectionLogging() {
1291         Intent sendIntent = createSendTextIntent();
1292         // We need app targets for direct targets to get displayed
1293         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1294         setupResolverControllers(resolvedComponentInfos);
1295 
1296         // create test shortcut loader factory, remember loaders and their callbacks
1297         SparseArray<Pair<ShortcutLoader, Consumer<ShortcutLoader.Result>>> shortcutLoaders =
1298                 createShortcutLoaderFactory();
1299 
1300         // Start activity
1301         final IChooserWrapper activity = (IChooserWrapper)
1302                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1303         waitForIdle();
1304 
1305         // verify that ShortcutLoader was queried
1306         ArgumentCaptor<DisplayResolveInfo[]> appTargets =
1307                 ArgumentCaptor.forClass(DisplayResolveInfo[].class);
1308         verify(shortcutLoaders.get(0).first, times(1)).queryShortcuts(appTargets.capture());
1309 
1310         // send shortcuts
1311         assertThat(
1312                 "Wrong number of app targets",
1313                 appTargets.getValue().length,
1314                 is(resolvedComponentInfos.size()));
1315         List<ChooserTarget> serviceTargets = createDirectShareTargets(1, "");
1316         ShortcutLoader.Result result = new ShortcutLoader.Result(
1317                 true,
1318                 appTargets.getValue(),
1319                 new ShortcutLoader.ShortcutResultInfo[] {
1320                         new ShortcutLoader.ShortcutResultInfo(
1321                                 appTargets.getValue()[0],
1322                                 serviceTargets
1323                         )
1324                 },
1325                 new HashMap<>(),
1326                 new HashMap<>()
1327         );
1328         activity.getMainExecutor().execute(() -> shortcutLoaders.get(0).second.accept(result));
1329         waitForIdle();
1330 
1331         final ChooserListAdapter activeAdapter = activity.getAdapter();
1332         assertThat(
1333                 "Chooser should have 3 targets (2 apps, 1 direct)",
1334                 activeAdapter.getCount(),
1335                 is(3));
1336         assertThat(
1337                 "Chooser should have exactly one selectable direct target",
1338                 activeAdapter.getSelectableServiceTargetCount(),
1339                 is(1));
1340         assertThat(
1341                 "The resolver info must match the resolver info used to create the target",
1342                 activeAdapter.getItem(0).getResolveInfo(),
1343                 is(resolvedComponentInfos.get(0).getResolveInfoAt(0)));
1344 
1345         // Click on the direct target
1346         String name = serviceTargets.get(0).getTitle().toString();
1347         onView(withText(name))
1348                 .perform(click());
1349         waitForIdle();
1350 
1351         ArgumentCaptor<HashedStringCache.HashResult> hashCaptor =
1352                 ArgumentCaptor.forClass(HashedStringCache.HashResult.class);
1353         verify(activity.getChooserActivityLogger(), times(1)).logShareTargetSelected(
1354                 eq(ChooserActivityLogger.SELECTION_TYPE_SERVICE),
1355                 /* packageName= */ any(),
1356                 /* positionPicked= */ anyInt(),
1357                 /* directTargetAlsoRanked= */ eq(-1),
1358                 /* numCallerProvided= */ anyInt(),
1359                 /* directTargetHashed= */ hashCaptor.capture(),
1360                 /* isPinned= */ anyBoolean(),
1361                 /* successfullySelected= */ anyBoolean(),
1362                 /* selectionCost= */ anyLong());
1363         String hashedName = hashCaptor.getValue().hashedString;
1364         assertThat(
1365                 "Hash is not predictable but must be obfuscated",
1366                 hashedName, is(not(name)));
1367     }
1368 
1369     // This test is too long and too slow and should not be taken as an example for future tests.
1370     @Test
testDirectTargetLoggingWithRankedAppTarget()1371     public void testDirectTargetLoggingWithRankedAppTarget() {
1372         Intent sendIntent = createSendTextIntent();
1373         // We need app targets for direct targets to get displayed
1374         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1375         setupResolverControllers(resolvedComponentInfos);
1376 
1377         // create test shortcut loader factory, remember loaders and their callbacks
1378         SparseArray<Pair<ShortcutLoader, Consumer<ShortcutLoader.Result>>> shortcutLoaders =
1379                 createShortcutLoaderFactory();
1380 
1381         // Start activity
1382         final IChooserWrapper activity = (IChooserWrapper)
1383                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1384         waitForIdle();
1385 
1386         // verify that ShortcutLoader was queried
1387         ArgumentCaptor<DisplayResolveInfo[]> appTargets =
1388                 ArgumentCaptor.forClass(DisplayResolveInfo[].class);
1389         verify(shortcutLoaders.get(0).first, times(1)).queryShortcuts(appTargets.capture());
1390 
1391         // send shortcuts
1392         assertThat(
1393                 "Wrong number of app targets",
1394                 appTargets.getValue().length,
1395                 is(resolvedComponentInfos.size()));
1396         List<ChooserTarget> serviceTargets = createDirectShareTargets(
1397                 1,
1398                 resolvedComponentInfos.get(0).getResolveInfoAt(0).activityInfo.packageName);
1399         ShortcutLoader.Result result = new ShortcutLoader.Result(
1400                 true,
1401                 appTargets.getValue(),
1402                 new ShortcutLoader.ShortcutResultInfo[] {
1403                         new ShortcutLoader.ShortcutResultInfo(
1404                                 appTargets.getValue()[0],
1405                                 serviceTargets
1406                         )
1407                 },
1408                 new HashMap<>(),
1409                 new HashMap<>()
1410         );
1411         activity.getMainExecutor().execute(() -> shortcutLoaders.get(0).second.accept(result));
1412         waitForIdle();
1413 
1414         final ChooserListAdapter activeAdapter = activity.getAdapter();
1415         assertThat(
1416                 "Chooser should have 3 targets (2 apps, 1 direct)",
1417                 activeAdapter.getCount(),
1418                 is(3));
1419         assertThat(
1420                 "Chooser should have exactly one selectable direct target",
1421                 activeAdapter.getSelectableServiceTargetCount(),
1422                 is(1));
1423         assertThat(
1424                 "The resolver info must match the resolver info used to create the target",
1425                 activeAdapter.getItem(0).getResolveInfo(),
1426                 is(resolvedComponentInfos.get(0).getResolveInfoAt(0)));
1427 
1428         // Click on the direct target
1429         String name = serviceTargets.get(0).getTitle().toString();
1430         onView(withText(name))
1431                 .perform(click());
1432         waitForIdle();
1433 
1434         verify(activity.getChooserActivityLogger(), times(1)).logShareTargetSelected(
1435                 eq(ChooserActivityLogger.SELECTION_TYPE_SERVICE),
1436                 /* packageName= */ any(),
1437                 /* positionPicked= */ anyInt(),
1438                 /* directTargetAlsoRanked= */ eq(0),
1439                 /* numCallerProvided= */ anyInt(),
1440                 /* directTargetHashed= */ any(),
1441                 /* isPinned= */ anyBoolean(),
1442                 /* successfullySelected= */ anyBoolean(),
1443                 /* selectionCost= */ anyLong());
1444     }
1445 
1446     @Test
testShortcutTargetWithApplyAppLimits()1447     public void testShortcutTargetWithApplyAppLimits() {
1448         // Set up resources
1449         ChooserActivityOverrideData.getInstance().resources = Mockito.spy(
1450                 InstrumentationRegistry.getInstrumentation().getContext().getResources());
1451         when(
1452                 ChooserActivityOverrideData
1453                         .getInstance()
1454                         .resources
1455                         .getInteger(R.integer.config_maxShortcutTargetsPerApp))
1456                 .thenReturn(1);
1457         Intent sendIntent = createSendTextIntent();
1458         // We need app targets for direct targets to get displayed
1459         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1460         setupResolverControllers(resolvedComponentInfos);
1461 
1462         // create test shortcut loader factory, remember loaders and their callbacks
1463         SparseArray<Pair<ShortcutLoader, Consumer<ShortcutLoader.Result>>> shortcutLoaders =
1464                 createShortcutLoaderFactory();
1465 
1466         // Start activity
1467         final IChooserWrapper activity = (IChooserWrapper) mActivityRule
1468                 .launchActivity(Intent.createChooser(sendIntent, null));
1469         waitForIdle();
1470 
1471         // verify that ShortcutLoader was queried
1472         ArgumentCaptor<DisplayResolveInfo[]> appTargets =
1473                 ArgumentCaptor.forClass(DisplayResolveInfo[].class);
1474         verify(shortcutLoaders.get(0).first, times(1)).queryShortcuts(appTargets.capture());
1475 
1476         // send shortcuts
1477         assertThat(
1478                 "Wrong number of app targets",
1479                 appTargets.getValue().length,
1480                 is(resolvedComponentInfos.size()));
1481         List<ChooserTarget> serviceTargets = createDirectShareTargets(
1482                 2,
1483                 resolvedComponentInfos.get(0).getResolveInfoAt(0).activityInfo.packageName);
1484         ShortcutLoader.Result result = new ShortcutLoader.Result(
1485                 true,
1486                 appTargets.getValue(),
1487                 new ShortcutLoader.ShortcutResultInfo[] {
1488                         new ShortcutLoader.ShortcutResultInfo(
1489                                 appTargets.getValue()[0],
1490                                 serviceTargets
1491                         )
1492                 },
1493                 new HashMap<>(),
1494                 new HashMap<>()
1495         );
1496         activity.getMainExecutor().execute(() -> shortcutLoaders.get(0).second.accept(result));
1497         waitForIdle();
1498 
1499         final ChooserListAdapter activeAdapter = activity.getAdapter();
1500         assertThat(
1501                 "Chooser should have 3 targets (2 apps, 1 direct)",
1502                 activeAdapter.getCount(),
1503                 is(3));
1504         assertThat(
1505                 "Chooser should have exactly one selectable direct target",
1506                 activeAdapter.getSelectableServiceTargetCount(),
1507                 is(1));
1508         assertThat(
1509                 "The resolver info must match the resolver info used to create the target",
1510                 activeAdapter.getItem(0).getResolveInfo(),
1511                 is(resolvedComponentInfos.get(0).getResolveInfoAt(0)));
1512         assertThat(
1513                 "The display label must match",
1514                 activeAdapter.getItem(0).getDisplayLabel(),
1515                 is("testTitle0"));
1516     }
1517 
1518     @Test
testShortcutTargetWithoutApplyAppLimits()1519     public void testShortcutTargetWithoutApplyAppLimits() {
1520         setDeviceConfigProperty(
1521                 SystemUiDeviceConfigFlags.APPLY_SHARING_APP_LIMITS_IN_SYSUI,
1522                 Boolean.toString(false));
1523         // Set up resources
1524         ChooserActivityOverrideData.getInstance().resources = Mockito.spy(
1525                 InstrumentationRegistry.getInstrumentation().getContext().getResources());
1526         when(
1527                 ChooserActivityOverrideData
1528                         .getInstance()
1529                         .resources
1530                         .getInteger(R.integer.config_maxShortcutTargetsPerApp))
1531                 .thenReturn(1);
1532         Intent sendIntent = createSendTextIntent();
1533         // We need app targets for direct targets to get displayed
1534         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1535         setupResolverControllers(resolvedComponentInfos);
1536 
1537         // create test shortcut loader factory, remember loaders and their callbacks
1538         SparseArray<Pair<ShortcutLoader, Consumer<ShortcutLoader.Result>>> shortcutLoaders =
1539                 createShortcutLoaderFactory();
1540 
1541         // Start activity
1542         final IChooserWrapper activity = (IChooserWrapper)
1543                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1544         waitForIdle();
1545 
1546         // verify that ShortcutLoader was queried
1547         ArgumentCaptor<DisplayResolveInfo[]> appTargets =
1548                 ArgumentCaptor.forClass(DisplayResolveInfo[].class);
1549         verify(shortcutLoaders.get(0).first, times(1)).queryShortcuts(appTargets.capture());
1550 
1551         // send shortcuts
1552         assertThat(
1553                 "Wrong number of app targets",
1554                 appTargets.getValue().length,
1555                 is(resolvedComponentInfos.size()));
1556         List<ChooserTarget> serviceTargets = createDirectShareTargets(
1557                 2,
1558                 resolvedComponentInfos.get(0).getResolveInfoAt(0).activityInfo.packageName);
1559         ShortcutLoader.Result result = new ShortcutLoader.Result(
1560                 true,
1561                 appTargets.getValue(),
1562                 new ShortcutLoader.ShortcutResultInfo[] {
1563                         new ShortcutLoader.ShortcutResultInfo(
1564                                 appTargets.getValue()[0],
1565                                 serviceTargets
1566                         )
1567                 },
1568                 new HashMap<>(),
1569                 new HashMap<>()
1570         );
1571         activity.getMainExecutor().execute(() -> shortcutLoaders.get(0).second.accept(result));
1572         waitForIdle();
1573 
1574         final ChooserListAdapter activeAdapter = activity.getAdapter();
1575         assertThat(
1576                 "Chooser should have 4 targets (2 apps, 2 direct)",
1577                 activeAdapter.getCount(),
1578                 is(4));
1579         assertThat(
1580                 "Chooser should have exactly two selectable direct target",
1581                 activeAdapter.getSelectableServiceTargetCount(),
1582                 is(2));
1583         assertThat(
1584                 "The resolver info must match the resolver info used to create the target",
1585                 activeAdapter.getItem(0).getResolveInfo(),
1586                 is(resolvedComponentInfos.get(0).getResolveInfoAt(0)));
1587         assertThat(
1588                 "The display label must match",
1589                 activeAdapter.getItem(0).getDisplayLabel(),
1590                 is("testTitle0"));
1591         assertThat(
1592                 "The display label must match",
1593                 activeAdapter.getItem(1).getDisplayLabel(),
1594                 is("testTitle1"));
1595     }
1596 
1597     @Test
testLaunchWithCallerProvidedTarget()1598     public void testLaunchWithCallerProvidedTarget() {
1599         setDeviceConfigProperty(
1600                 SystemUiDeviceConfigFlags.APPLY_SHARING_APP_LIMITS_IN_SYSUI,
1601                 Boolean.toString(false));
1602         // Set up resources
1603         ChooserActivityOverrideData.getInstance().resources = Mockito.spy(
1604                 InstrumentationRegistry.getInstrumentation().getContext().getResources());
1605         when(
1606                 ChooserActivityOverrideData
1607                         .getInstance()
1608                         .resources
1609                         .getInteger(R.integer.config_maxShortcutTargetsPerApp))
1610                 .thenReturn(1);
1611 
1612         // We need app targets for direct targets to get displayed
1613         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1614         setupResolverControllers(resolvedComponentInfos);
1615 
1616         // set caller-provided target
1617         Intent chooserIntent = Intent.createChooser(createSendTextIntent(), null);
1618         String callerTargetLabel = "Caller Target";
1619         ChooserTarget[] targets = new ChooserTarget[] {
1620                 new ChooserTarget(
1621                         callerTargetLabel,
1622                         Icon.createWithBitmap(createBitmap()),
1623                         0.1f,
1624                         resolvedComponentInfos.get(0).name,
1625                         new Bundle())
1626         };
1627         chooserIntent.putExtra(Intent.EXTRA_CHOOSER_TARGETS, targets);
1628 
1629         // create test shortcut loader factory, remember loaders and their callbacks
1630         SparseArray<Pair<ShortcutLoader, Consumer<ShortcutLoader.Result>>> shortcutLoaders =
1631                 createShortcutLoaderFactory();
1632 
1633         // Start activity
1634         final IChooserWrapper activity = (IChooserWrapper)
1635                 mActivityRule.launchActivity(chooserIntent);
1636         waitForIdle();
1637 
1638         // verify that ShortcutLoader was queried
1639         ArgumentCaptor<DisplayResolveInfo[]> appTargets =
1640                 ArgumentCaptor.forClass(DisplayResolveInfo[].class);
1641         verify(shortcutLoaders.get(0).first, times(1)).queryShortcuts(appTargets.capture());
1642 
1643         // send shortcuts
1644         assertThat(
1645                 "Wrong number of app targets",
1646                 appTargets.getValue().length,
1647                 is(resolvedComponentInfos.size()));
1648         ShortcutLoader.Result result = new ShortcutLoader.Result(
1649                 true,
1650                 appTargets.getValue(),
1651                 new ShortcutLoader.ShortcutResultInfo[0],
1652                 new HashMap<>(),
1653                 new HashMap<>());
1654         activity.getMainExecutor().execute(() -> shortcutLoaders.get(0).second.accept(result));
1655         waitForIdle();
1656 
1657         final ChooserListAdapter activeAdapter = activity.getAdapter();
1658         assertThat(
1659                 "Chooser should have 3 targets (2 apps, 1 direct)",
1660                 activeAdapter.getCount(),
1661                 is(3));
1662         assertThat(
1663                 "Chooser should have exactly two selectable direct target",
1664                 activeAdapter.getSelectableServiceTargetCount(),
1665                 is(1));
1666         assertThat(
1667                 "The display label must match",
1668                 activeAdapter.getItem(0).getDisplayLabel(),
1669                 is(callerTargetLabel));
1670     }
1671 
1672     @Test
1673     @RequireFeatureFlags(
1674             flags = { Flags.SHARESHEET_CUSTOM_ACTIONS_NAME },
1675             values = { true })
testLaunchWithCustomAction()1676     public void testLaunchWithCustomAction() throws InterruptedException {
1677         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1678         setupResolverControllers(resolvedComponentInfos);
1679 
1680         Context testContext = InstrumentationRegistry.getInstrumentation().getContext();
1681         final String customActionLabel = "Custom Action";
1682         final String testAction = "test-broadcast-receiver-action";
1683         Intent chooserIntent = Intent.createChooser(createSendTextIntent(), null);
1684         chooserIntent.putExtra(
1685                 Intent.EXTRA_CHOOSER_CUSTOM_ACTIONS,
1686                 new ChooserAction[] {
1687                         new ChooserAction.Builder(
1688                                 Icon.createWithResource("", Resources.ID_NULL),
1689                                 customActionLabel,
1690                                 PendingIntent.getBroadcast(
1691                                         testContext,
1692                                         123,
1693                                         new Intent(testAction),
1694                                         PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT))
1695                                 .build()
1696                 });
1697         // Start activity
1698         mActivityRule.launchActivity(chooserIntent);
1699         waitForIdle();
1700 
1701         final CountDownLatch broadcastInvoked = new CountDownLatch(1);
1702         BroadcastReceiver testReceiver = new BroadcastReceiver() {
1703             @Override
1704             public void onReceive(Context context, Intent intent) {
1705                 broadcastInvoked.countDown();
1706             }
1707         };
1708         testContext.registerReceiver(testReceiver, new IntentFilter(testAction));
1709 
1710         try {
1711             onView(withText(customActionLabel)).perform(click());
1712             broadcastInvoked.await();
1713         } finally {
1714             testContext.unregisterReceiver(testReceiver);
1715         }
1716     }
1717 
1718     @Test
1719     @RequireFeatureFlags(
1720             flags = { Flags.SHARESHEET_RESELECTION_ACTION_NAME },
1721             values = { true })
testLaunchWithShareModification()1722     public void testLaunchWithShareModification() throws InterruptedException {
1723         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1724         setupResolverControllers(resolvedComponentInfos);
1725 
1726         Context testContext = InstrumentationRegistry.getInstrumentation().getContext();
1727         final String modifyShareAction = "test-broadcast-receiver-action";
1728         Intent chooserIntent = Intent.createChooser(createSendTextIntent(), null);
1729         chooserIntent.putExtra(
1730                 Intent.EXTRA_CHOOSER_MODIFY_SHARE_ACTION,
1731                 PendingIntent.getBroadcast(
1732                         testContext,
1733                         123,
1734                         new Intent(modifyShareAction),
1735                         PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT));
1736         // Start activity
1737         mActivityRule.launchActivity(chooserIntent);
1738         waitForIdle();
1739 
1740         final CountDownLatch broadcastInvoked = new CountDownLatch(1);
1741         BroadcastReceiver testReceiver = new BroadcastReceiver() {
1742             @Override
1743             public void onReceive(Context context, Intent intent) {
1744                 broadcastInvoked.countDown();
1745             }
1746         };
1747         testContext.registerReceiver(testReceiver, new IntentFilter(modifyShareAction));
1748 
1749         try {
1750             onView(withText(R.string.select_text)).perform(click());
1751             broadcastInvoked.await();
1752         } finally {
1753             testContext.unregisterReceiver(testReceiver);
1754         }
1755     }
1756 
1757     @Test
testUpdateMaxTargetsPerRow_columnCountIsUpdated()1758     public void testUpdateMaxTargetsPerRow_columnCountIsUpdated() throws InterruptedException {
1759         updateMaxTargetsPerRowResource(/* targetsPerRow= */ 4);
1760         givenAppTargets(/* appCount= */ 16);
1761         Intent sendIntent = createSendTextIntent();
1762         final ChooserActivity activity =
1763                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1764 
1765         updateMaxTargetsPerRowResource(/* targetsPerRow= */ 6);
1766         InstrumentationRegistry.getInstrumentation()
1767                 .runOnMainSync(() -> activity.onConfigurationChanged(
1768                         InstrumentationRegistry.getInstrumentation()
1769                                 .getContext().getResources().getConfiguration()));
1770 
1771         waitForIdle();
1772         onView(withId(com.android.internal.R.id.resolver_list))
1773                 .check(matches(withGridColumnCount(6)));
1774     }
1775 
1776     // This test is too long and too slow and should not be taken as an example for future tests.
1777     @Test @Ignore
testDirectTargetLoggingWithAppTargetNotRankedPortrait()1778     public void testDirectTargetLoggingWithAppTargetNotRankedPortrait()
1779             throws InterruptedException {
1780         testDirectTargetLoggingWithAppTargetNotRanked(Configuration.ORIENTATION_PORTRAIT, 4);
1781     }
1782 
1783     @Test @Ignore
testDirectTargetLoggingWithAppTargetNotRankedLandscape()1784     public void testDirectTargetLoggingWithAppTargetNotRankedLandscape()
1785             throws InterruptedException {
1786         testDirectTargetLoggingWithAppTargetNotRanked(Configuration.ORIENTATION_LANDSCAPE, 8);
1787     }
1788 
testDirectTargetLoggingWithAppTargetNotRanked( int orientation, int appTargetsExpected)1789     private void testDirectTargetLoggingWithAppTargetNotRanked(
1790             int orientation, int appTargetsExpected) {
1791         Configuration configuration =
1792                 new Configuration(InstrumentationRegistry.getInstrumentation().getContext()
1793                         .getResources().getConfiguration());
1794         configuration.orientation = orientation;
1795 
1796         ChooserActivityOverrideData.getInstance().resources = Mockito.spy(
1797                 InstrumentationRegistry.getInstrumentation().getContext().getResources());
1798         when(
1799                 ChooserActivityOverrideData
1800                         .getInstance()
1801                         .resources
1802                         .getConfiguration())
1803                 .thenReturn(configuration);
1804 
1805         Intent sendIntent = createSendTextIntent();
1806         // We need app targets for direct targets to get displayed
1807         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(15);
1808         setupResolverControllers(resolvedComponentInfos);
1809 
1810         // Create direct share target
1811         List<ChooserTarget> serviceTargets = createDirectShareTargets(1,
1812                 resolvedComponentInfos.get(14).getResolveInfoAt(0).activityInfo.packageName);
1813         ResolveInfo ri = ResolverDataProvider.createResolveInfo(16, 0);
1814 
1815         // Start activity
1816         final IChooserWrapper wrapper = (IChooserWrapper)
1817                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1818         // Insert the direct share target
1819         Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos = new HashMap<>();
1820         directShareToShortcutInfos.put(serviceTargets.get(0), null);
1821         InstrumentationRegistry.getInstrumentation().runOnMainSync(
1822                 () -> wrapper.getAdapter().addServiceResults(
1823                         wrapper.createTestDisplayResolveInfo(sendIntent,
1824                                 ri,
1825                                 "testLabel",
1826                                 "testInfo",
1827                                 sendIntent,
1828                                 /* resolveInfoPresentationGetter */ null),
1829                         serviceTargets,
1830                         TARGET_TYPE_CHOOSER_TARGET,
1831                         directShareToShortcutInfos,
1832                         /* directShareToAppTargets */ null)
1833         );
1834 
1835         assertThat(
1836                 String.format("Chooser should have %d targets (%d apps, 1 direct, 15 A-Z)",
1837                         appTargetsExpected + 16, appTargetsExpected),
1838                 wrapper.getAdapter().getCount(), is(appTargetsExpected + 16));
1839         assertThat("Chooser should have exactly one selectable direct target",
1840                 wrapper.getAdapter().getSelectableServiceTargetCount(), is(1));
1841         assertThat("The resolver info must match the resolver info used to create the target",
1842                 wrapper.getAdapter().getItem(0).getResolveInfo(), is(ri));
1843 
1844         // Click on the direct target
1845         String name = serviceTargets.get(0).getTitle().toString();
1846         onView(withText(name))
1847                 .perform(click());
1848         waitForIdle();
1849 
1850         ChooserActivityLogger logger = wrapper.getChooserActivityLogger();
1851         verify(logger, times(1)).logShareTargetSelected(
1852                 eq(ChooserActivityLogger.SELECTION_TYPE_SERVICE),
1853                 /* packageName= */ any(),
1854                 /* positionPicked= */ anyInt(),
1855                 // The packages sholdn't match for app target and direct target:
1856                 /* directTargetAlsoRanked= */ eq(-1),
1857                 /* numCallerProvided= */ anyInt(),
1858                 /* directTargetHashed= */ any(),
1859                 /* isPinned= */ anyBoolean(),
1860                 /* successfullySelected= */ anyBoolean(),
1861                 /* selectionCost= */ anyLong());
1862     }
1863 
1864     @Test
testWorkTab_displayedWhenWorkProfileUserAvailable()1865     public void testWorkTab_displayedWhenWorkProfileUserAvailable() {
1866         Intent sendIntent = createSendTextIntent();
1867         sendIntent.setType(TEST_MIME_TYPE);
1868         markWorkProfileUserAvailable();
1869 
1870         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
1871         waitForIdle();
1872 
1873         onView(withId(android.R.id.tabs)).check(matches(isDisplayed()));
1874     }
1875 
1876     @Test
testWorkTab_hiddenWhenWorkProfileUserNotAvailable()1877     public void testWorkTab_hiddenWhenWorkProfileUserNotAvailable() {
1878         Intent sendIntent = createSendTextIntent();
1879         sendIntent.setType(TEST_MIME_TYPE);
1880 
1881         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
1882         waitForIdle();
1883 
1884         onView(withId(android.R.id.tabs)).check(matches(not(isDisplayed())));
1885     }
1886 
1887     @Test
testWorkTab_eachTabUsesExpectedAdapter()1888     public void testWorkTab_eachTabUsesExpectedAdapter() {
1889         int personalProfileTargets = 3;
1890         int otherProfileTargets = 1;
1891         List<ResolvedComponentInfo> personalResolvedComponentInfos =
1892                 createResolvedComponentsForTestWithOtherProfile(
1893                         personalProfileTargets + otherProfileTargets, /* userID */ 10);
1894         int workProfileTargets = 4;
1895         List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(
1896                 workProfileTargets);
1897         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
1898         Intent sendIntent = createSendTextIntent();
1899         sendIntent.setType(TEST_MIME_TYPE);
1900         markWorkProfileUserAvailable();
1901 
1902         final IChooserWrapper activity = (IChooserWrapper)
1903                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
1904         waitForIdle();
1905 
1906         assertThat(activity.getCurrentUserHandle().getIdentifier(), is(0));
1907         onView(withText(R.string.resolver_work_tab)).perform(click());
1908         assertThat(activity.getCurrentUserHandle().getIdentifier(), is(10));
1909         assertThat(activity.getPersonalListAdapter().getCount(), is(personalProfileTargets));
1910         assertThat(activity.getWorkListAdapter().getCount(), is(workProfileTargets));
1911     }
1912 
1913     @Test
testWorkTab_workProfileHasExpectedNumberOfTargets()1914     public void testWorkTab_workProfileHasExpectedNumberOfTargets() throws InterruptedException {
1915         markWorkProfileUserAvailable();
1916         int workProfileTargets = 4;
1917         List<ResolvedComponentInfo> personalResolvedComponentInfos =
1918                 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
1919         List<ResolvedComponentInfo> workResolvedComponentInfos =
1920                 createResolvedComponentsForTest(workProfileTargets);
1921         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
1922         Intent sendIntent = createSendTextIntent();
1923         sendIntent.setType(TEST_MIME_TYPE);
1924 
1925         final IChooserWrapper activity = (IChooserWrapper)
1926                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
1927         waitForIdle();
1928         onView(withText(R.string.resolver_work_tab)).perform(click());
1929         waitForIdle();
1930 
1931         assertThat(activity.getWorkListAdapter().getCount(), is(workProfileTargets));
1932     }
1933 
1934     @Test @Ignore
testWorkTab_selectingWorkTabAppOpensAppInWorkProfile()1935     public void testWorkTab_selectingWorkTabAppOpensAppInWorkProfile() {
1936         markWorkProfileUserAvailable();
1937         List<ResolvedComponentInfo> personalResolvedComponentInfos =
1938                 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
1939         int workProfileTargets = 4;
1940         List<ResolvedComponentInfo> workResolvedComponentInfos =
1941                 createResolvedComponentsForTest(workProfileTargets);
1942         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
1943         Intent sendIntent = createSendTextIntent();
1944         sendIntent.setType(TEST_MIME_TYPE);
1945         ResolveInfo[] chosen = new ResolveInfo[1];
1946         ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
1947             chosen[0] = targetInfo.getResolveInfo();
1948             return true;
1949         };
1950 
1951         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
1952         waitForIdle();
1953         onView(withText(R.string.resolver_work_tab)).perform(click());
1954         waitForIdle();
1955 
1956         onView(first(allOf(
1957                 withText(workResolvedComponentInfos.get(0)
1958                         .getResolveInfoAt(0).activityInfo.applicationInfo.name),
1959                 isDisplayed())))
1960                 .perform(click());
1961         waitForIdle();
1962         assertThat(chosen[0], is(workResolvedComponentInfos.get(0).getResolveInfoAt(0)));
1963     }
1964 
1965     @Test
testWorkTab_crossProfileIntentsDisabled_personalToWork_emptyStateShown()1966     public void testWorkTab_crossProfileIntentsDisabled_personalToWork_emptyStateShown() {
1967         markWorkProfileUserAvailable();
1968         int workProfileTargets = 4;
1969         List<ResolvedComponentInfo> personalResolvedComponentInfos =
1970                 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
1971         List<ResolvedComponentInfo> workResolvedComponentInfos =
1972                 createResolvedComponentsForTest(workProfileTargets);
1973         ChooserActivityOverrideData.getInstance().hasCrossProfileIntents = false;
1974         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
1975         Intent sendIntent = createSendTextIntent();
1976         sendIntent.setType(TEST_MIME_TYPE);
1977 
1978         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
1979         waitForIdle();
1980         onView(withText(R.string.resolver_work_tab)).perform(click());
1981         waitForIdle();
1982         onView(withId(com.android.internal.R.id.contentPanel))
1983                 .perform(swipeUp());
1984 
1985         onView(withText(R.string.resolver_cross_profile_blocked))
1986                 .check(matches(isDisplayed()));
1987     }
1988 
1989     @Test
testWorkTab_workProfileDisabled_emptyStateShown()1990     public void testWorkTab_workProfileDisabled_emptyStateShown() {
1991         markWorkProfileUserAvailable();
1992         int workProfileTargets = 4;
1993         List<ResolvedComponentInfo> personalResolvedComponentInfos =
1994                 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
1995         List<ResolvedComponentInfo> workResolvedComponentInfos =
1996                 createResolvedComponentsForTest(workProfileTargets);
1997         ChooserActivityOverrideData.getInstance().isQuietModeEnabled = true;
1998         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
1999         Intent sendIntent = createSendTextIntent();
2000         sendIntent.setType(TEST_MIME_TYPE);
2001 
2002         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
2003         waitForIdle();
2004         onView(withId(com.android.internal.R.id.contentPanel))
2005                 .perform(swipeUp());
2006         onView(withText(R.string.resolver_work_tab)).perform(click());
2007         waitForIdle();
2008 
2009         onView(withText(R.string.resolver_turn_on_work_apps))
2010                 .check(matches(isDisplayed()));
2011     }
2012 
2013     @Test
testWorkTab_noWorkAppsAvailable_emptyStateShown()2014     public void testWorkTab_noWorkAppsAvailable_emptyStateShown() {
2015         markWorkProfileUserAvailable();
2016         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2017                 createResolvedComponentsForTest(3);
2018         List<ResolvedComponentInfo> workResolvedComponentInfos =
2019                 createResolvedComponentsForTest(0);
2020         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
2021         Intent sendIntent = createSendTextIntent();
2022         sendIntent.setType(TEST_MIME_TYPE);
2023 
2024         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
2025         waitForIdle();
2026         onView(withId(com.android.internal.R.id.contentPanel))
2027                 .perform(swipeUp());
2028         onView(withText(R.string.resolver_work_tab)).perform(click());
2029         waitForIdle();
2030 
2031         onView(withText(R.string.resolver_no_work_apps_available))
2032                 .check(matches(isDisplayed()));
2033     }
2034 
2035     @Ignore // b/220067877
2036     @Test
testWorkTab_xProfileOff_noAppsAvailable_workOff_xProfileOffEmptyStateShown()2037     public void testWorkTab_xProfileOff_noAppsAvailable_workOff_xProfileOffEmptyStateShown() {
2038         markWorkProfileUserAvailable();
2039         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2040                 createResolvedComponentsForTest(3);
2041         List<ResolvedComponentInfo> workResolvedComponentInfos =
2042                 createResolvedComponentsForTest(0);
2043         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
2044         ChooserActivityOverrideData.getInstance().isQuietModeEnabled = true;
2045         ChooserActivityOverrideData.getInstance().hasCrossProfileIntents = false;
2046         Intent sendIntent = createSendTextIntent();
2047         sendIntent.setType(TEST_MIME_TYPE);
2048 
2049         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
2050         waitForIdle();
2051         onView(withId(com.android.internal.R.id.contentPanel))
2052                 .perform(swipeUp());
2053         onView(withText(R.string.resolver_work_tab)).perform(click());
2054         waitForIdle();
2055 
2056         onView(withText(R.string.resolver_cross_profile_blocked))
2057                 .check(matches(isDisplayed()));
2058     }
2059 
2060     @Test
testWorkTab_noAppsAvailable_workOff_noAppsAvailableEmptyStateShown()2061     public void testWorkTab_noAppsAvailable_workOff_noAppsAvailableEmptyStateShown() {
2062         markWorkProfileUserAvailable();
2063         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2064                 createResolvedComponentsForTest(3);
2065         List<ResolvedComponentInfo> workResolvedComponentInfos =
2066                 createResolvedComponentsForTest(0);
2067         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
2068         ChooserActivityOverrideData.getInstance().isQuietModeEnabled = true;
2069         Intent sendIntent = createSendTextIntent();
2070         sendIntent.setType(TEST_MIME_TYPE);
2071 
2072         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
2073         waitForIdle();
2074         onView(withId(com.android.internal.R.id.contentPanel))
2075                 .perform(swipeUp());
2076         onView(withText(R.string.resolver_work_tab)).perform(click());
2077         waitForIdle();
2078 
2079         onView(withText(R.string.resolver_no_work_apps_available))
2080                 .check(matches(isDisplayed()));
2081     }
2082 
2083     @Test @Ignore("b/222124533")
testAppTargetLogging()2084     public void testAppTargetLogging() throws InterruptedException {
2085         Intent sendIntent = createSendTextIntent();
2086         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
2087 
2088         setupResolverControllers(resolvedComponentInfos);
2089 
2090         final IChooserWrapper activity = (IChooserWrapper)
2091                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
2092         waitForIdle();
2093 
2094         // TODO(b/222124533): other test cases use a timeout to make sure that the UI is fully
2095         // populated; without one, this test flakes. Ideally we should address the need for a
2096         // timeout everywhere instead of introducing one to fix this particular test.
2097 
2098         assertThat(activity.getAdapter().getCount(), is(2));
2099         onView(withId(com.android.internal.R.id.profile_button)).check(doesNotExist());
2100 
2101         ResolveInfo[] chosen = new ResolveInfo[1];
2102         ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
2103             chosen[0] = targetInfo.getResolveInfo();
2104             return true;
2105         };
2106 
2107         ResolveInfo toChoose = resolvedComponentInfos.get(0).getResolveInfoAt(0);
2108         onView(withText(toChoose.activityInfo.name))
2109                 .perform(click());
2110         waitForIdle();
2111 
2112         // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events.
2113     }
2114 
2115     @Test
testDirectTargetLogging()2116     public void testDirectTargetLogging() {
2117         Intent sendIntent = createSendTextIntent();
2118         // We need app targets for direct targets to get displayed
2119         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
2120         setupResolverControllers(resolvedComponentInfos);
2121 
2122         // create test shortcut loader factory, remember loaders and their callbacks
2123         SparseArray<Pair<ShortcutLoader, Consumer<ShortcutLoader.Result>>> shortcutLoaders =
2124                 new SparseArray<>();
2125         ChooserActivityOverrideData.getInstance().shortcutLoaderFactory =
2126                 (userHandle, callback) -> {
2127                     Pair<ShortcutLoader, Consumer<ShortcutLoader.Result>> pair =
2128                             new Pair<>(mock(ShortcutLoader.class), callback);
2129                     shortcutLoaders.put(userHandle.getIdentifier(), pair);
2130                     return pair.first;
2131                 };
2132 
2133         // Start activity
2134         final IChooserWrapper activity = (IChooserWrapper)
2135                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
2136         waitForIdle();
2137 
2138         // verify that ShortcutLoader was queried
2139         ArgumentCaptor<DisplayResolveInfo[]> appTargets =
2140                 ArgumentCaptor.forClass(DisplayResolveInfo[].class);
2141         verify(shortcutLoaders.get(0).first, times(1))
2142                 .queryShortcuts(appTargets.capture());
2143 
2144         // send shortcuts
2145         assertThat(
2146                 "Wrong number of app targets",
2147                 appTargets.getValue().length,
2148                 is(resolvedComponentInfos.size()));
2149         List<ChooserTarget> serviceTargets = createDirectShareTargets(1,
2150                 resolvedComponentInfos.get(0).getResolveInfoAt(0).activityInfo.packageName);
2151         ShortcutLoader.Result result = new ShortcutLoader.Result(
2152                 // TODO: test another value as well
2153                 false,
2154                 appTargets.getValue(),
2155                 new ShortcutLoader.ShortcutResultInfo[] {
2156                         new ShortcutLoader.ShortcutResultInfo(
2157                                 appTargets.getValue()[0],
2158                                 serviceTargets
2159                         )
2160                 },
2161                 new HashMap<>(),
2162                 new HashMap<>()
2163         );
2164         activity.getMainExecutor().execute(() -> shortcutLoaders.get(0).second.accept(result));
2165         waitForIdle();
2166 
2167         assertThat("Chooser should have 3 targets (2 apps, 1 direct)",
2168                 activity.getAdapter().getCount(), is(3));
2169         assertThat("Chooser should have exactly one selectable direct target",
2170                 activity.getAdapter().getSelectableServiceTargetCount(), is(1));
2171         assertThat(
2172                 "The resolver info must match the resolver info used to create the target",
2173                 activity.getAdapter().getItem(0).getResolveInfo(),
2174                 is(resolvedComponentInfos.get(0).getResolveInfoAt(0)));
2175 
2176         // Click on the direct target
2177         String name = serviceTargets.get(0).getTitle().toString();
2178         onView(withText(name))
2179                 .perform(click());
2180         waitForIdle();
2181 
2182         ChooserActivityLogger logger = activity.getChooserActivityLogger();
2183         ArgumentCaptor<Integer> typeCaptor = ArgumentCaptor.forClass(Integer.class);
2184         verify(logger, times(1)).logShareTargetSelected(
2185                 eq(ChooserActivityLogger.SELECTION_TYPE_SERVICE),
2186                 /* packageName= */ any(),
2187                 /* positionPicked= */ anyInt(),
2188                 /* directTargetAlsoRanked= */ anyInt(),
2189                 /* numCallerProvided= */ anyInt(),
2190                 /* directTargetHashed= */ any(),
2191                 /* isPinned= */ anyBoolean(),
2192                 /* successfullySelected= */ anyBoolean(),
2193                 /* selectionCost= */ anyLong());
2194     }
2195 
2196     @Test
testDirectTargetPinningDialog()2197     public void testDirectTargetPinningDialog() {
2198         Intent sendIntent = createSendTextIntent();
2199         // We need app targets for direct targets to get displayed
2200         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
2201         setupResolverControllers(resolvedComponentInfos);
2202 
2203         // create test shortcut loader factory, remember loaders and their callbacks
2204         SparseArray<Pair<ShortcutLoader, Consumer<ShortcutLoader.Result>>> shortcutLoaders =
2205                 new SparseArray<>();
2206         ChooserActivityOverrideData.getInstance().shortcutLoaderFactory =
2207                 (userHandle, callback) -> {
2208                     Pair<ShortcutLoader, Consumer<ShortcutLoader.Result>> pair =
2209                             new Pair<>(mock(ShortcutLoader.class), callback);
2210                     shortcutLoaders.put(userHandle.getIdentifier(), pair);
2211                     return pair.first;
2212                 };
2213 
2214         // Start activity
2215         final IChooserWrapper activity = (IChooserWrapper)
2216                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
2217         waitForIdle();
2218 
2219         // verify that ShortcutLoader was queried
2220         ArgumentCaptor<DisplayResolveInfo[]> appTargets =
2221                 ArgumentCaptor.forClass(DisplayResolveInfo[].class);
2222         verify(shortcutLoaders.get(0).first, times(1))
2223                 .queryShortcuts(appTargets.capture());
2224 
2225         // send shortcuts
2226         List<ChooserTarget> serviceTargets = createDirectShareTargets(
2227                 1,
2228                 resolvedComponentInfos.get(0).getResolveInfoAt(0).activityInfo.packageName);
2229         ShortcutLoader.Result result = new ShortcutLoader.Result(
2230                 // TODO: test another value as well
2231                 false,
2232                 appTargets.getValue(),
2233                 new ShortcutLoader.ShortcutResultInfo[] {
2234                         new ShortcutLoader.ShortcutResultInfo(
2235                                 appTargets.getValue()[0],
2236                                 serviceTargets
2237                         )
2238                 },
2239                 new HashMap<>(),
2240                 new HashMap<>()
2241         );
2242         activity.getMainExecutor().execute(() -> shortcutLoaders.get(0).second.accept(result));
2243         waitForIdle();
2244 
2245         // Long-click on the direct target
2246         String name = serviceTargets.get(0).getTitle().toString();
2247         onView(withText(name)).perform(longClick());
2248         waitForIdle();
2249 
2250         onView(withId(R.id.chooser_dialog_content)).check(matches(isDisplayed()));
2251     }
2252 
2253     @Test @Ignore
testEmptyDirectRowLogging()2254     public void testEmptyDirectRowLogging() throws InterruptedException {
2255         Intent sendIntent = createSendTextIntent();
2256         // We need app targets for direct targets to get displayed
2257         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
2258         setupResolverControllers(resolvedComponentInfos);
2259 
2260         // Start activity
2261         final IChooserWrapper activity = (IChooserWrapper)
2262                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
2263 
2264         // Thread.sleep shouldn't be a thing in an integration test but it's
2265         // necessary here because of the way the code is structured
2266         Thread.sleep(3000);
2267 
2268         assertThat("Chooser should have 2 app targets",
2269                 activity.getAdapter().getCount(), is(2));
2270         assertThat("Chooser should have no direct targets",
2271                 activity.getAdapter().getSelectableServiceTargetCount(), is(0));
2272 
2273         // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events.
2274     }
2275 
2276     @Ignore // b/220067877
2277     @Test
testCopyTextToClipboardLogging()2278     public void testCopyTextToClipboardLogging() throws Exception {
2279         Intent sendIntent = createSendTextIntent();
2280         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
2281 
2282         setupResolverControllers(resolvedComponentInfos);
2283 
2284         final IChooserWrapper activity = (IChooserWrapper)
2285                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
2286         waitForIdle();
2287 
2288         onView(withId(com.android.internal.R.id.chooser_copy_button)).check(matches(isDisplayed()));
2289         onView(withId(com.android.internal.R.id.chooser_copy_button)).perform(click());
2290 
2291         // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events.
2292     }
2293 
2294     @Test @Ignore("b/222124533")
testSwitchProfileLogging()2295     public void testSwitchProfileLogging() throws InterruptedException {
2296         markWorkProfileUserAvailable();
2297         int workProfileTargets = 4;
2298         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2299                 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
2300         List<ResolvedComponentInfo> workResolvedComponentInfos =
2301                 createResolvedComponentsForTest(workProfileTargets);
2302         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
2303         Intent sendIntent = createSendTextIntent();
2304         sendIntent.setType(TEST_MIME_TYPE);
2305 
2306         final IChooserWrapper activity = (IChooserWrapper)
2307                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
2308         waitForIdle();
2309         onView(withText(R.string.resolver_work_tab)).perform(click());
2310         waitForIdle();
2311         onView(withText(R.string.resolver_personal_tab)).perform(click());
2312         waitForIdle();
2313 
2314         // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events.
2315     }
2316 
2317     @Test
testWorkTab_onePersonalTarget_emptyStateOnWorkTarget_autolaunch()2318     public void testWorkTab_onePersonalTarget_emptyStateOnWorkTarget_autolaunch() {
2319         markWorkProfileUserAvailable();
2320         int workProfileTargets = 4;
2321         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2322                 createResolvedComponentsForTestWithOtherProfile(2, /* userId */ 10);
2323         List<ResolvedComponentInfo> workResolvedComponentInfos =
2324                 createResolvedComponentsForTest(workProfileTargets);
2325         ChooserActivityOverrideData.getInstance().hasCrossProfileIntents = false;
2326         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
2327         Intent sendIntent = createSendTextIntent();
2328         ResolveInfo[] chosen = new ResolveInfo[1];
2329         ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
2330             chosen[0] = targetInfo.getResolveInfo();
2331             return true;
2332         };
2333 
2334         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "Test"));
2335         waitForIdle();
2336 
2337         assertThat(chosen[0], is(personalResolvedComponentInfos.get(1).getResolveInfoAt(0)));
2338     }
2339 
2340     @Test
testOneInitialIntent_noAutolaunch()2341     public void testOneInitialIntent_noAutolaunch() {
2342         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2343                 createResolvedComponentsForTest(1);
2344         setupResolverControllers(personalResolvedComponentInfos);
2345         Intent chooserIntent = createChooserIntent(createSendTextIntent(),
2346                 new Intent[] {new Intent("action.fake")});
2347         ResolveInfo[] chosen = new ResolveInfo[1];
2348         ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
2349             chosen[0] = targetInfo.getResolveInfo();
2350             return true;
2351         };
2352         ChooserActivityOverrideData.getInstance().packageManager = mock(PackageManager.class);
2353         ResolveInfo ri = createFakeResolveInfo();
2354         when(
2355                 ChooserActivityOverrideData
2356                         .getInstance().packageManager
2357                         .resolveActivity(any(Intent.class), any()))
2358                 .thenReturn(ri);
2359         waitForIdle();
2360 
2361         IChooserWrapper activity = (IChooserWrapper) mActivityRule.launchActivity(chooserIntent);
2362         waitForIdle();
2363 
2364         assertNull(chosen[0]);
2365         assertThat(activity
2366                 .getPersonalListAdapter().getCallerTargetCount(), is(1));
2367     }
2368 
2369     @Test
testWorkTab_withInitialIntents_workTabDoesNotIncludePersonalInitialIntents()2370     public void testWorkTab_withInitialIntents_workTabDoesNotIncludePersonalInitialIntents() {
2371         markWorkProfileUserAvailable();
2372         int workProfileTargets = 1;
2373         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2374                 createResolvedComponentsForTestWithOtherProfile(2, /* userId */ 10);
2375         List<ResolvedComponentInfo> workResolvedComponentInfos =
2376                 createResolvedComponentsForTest(workProfileTargets);
2377         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
2378         Intent[] initialIntents = {
2379                 new Intent("action.fake1"),
2380                 new Intent("action.fake2")
2381         };
2382         Intent chooserIntent = createChooserIntent(createSendTextIntent(), initialIntents);
2383         ChooserActivityOverrideData.getInstance().packageManager = mock(PackageManager.class);
2384         when(
2385                 ChooserActivityOverrideData
2386                         .getInstance()
2387                         .packageManager
2388                         .resolveActivity(any(Intent.class), any()))
2389                 .thenReturn(createFakeResolveInfo());
2390         waitForIdle();
2391 
2392         IChooserWrapper activity = (IChooserWrapper) mActivityRule.launchActivity(chooserIntent);
2393         waitForIdle();
2394 
2395         assertThat(activity.getPersonalListAdapter().getCallerTargetCount(), is(2));
2396         assertThat(activity.getWorkListAdapter().getCallerTargetCount(), is(0));
2397     }
2398 
2399     @Test
testWorkTab_xProfileIntentsDisabled_personalToWork_nonSendIntent_emptyStateShown()2400     public void testWorkTab_xProfileIntentsDisabled_personalToWork_nonSendIntent_emptyStateShown() {
2401         markWorkProfileUserAvailable();
2402         int workProfileTargets = 4;
2403         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2404                 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
2405         List<ResolvedComponentInfo> workResolvedComponentInfos =
2406                 createResolvedComponentsForTest(workProfileTargets);
2407         ChooserActivityOverrideData.getInstance().hasCrossProfileIntents = false;
2408         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
2409         Intent[] initialIntents = {
2410                 new Intent("action.fake1"),
2411                 new Intent("action.fake2")
2412         };
2413         Intent chooserIntent = createChooserIntent(new Intent(), initialIntents);
2414         ChooserActivityOverrideData.getInstance().packageManager = mock(PackageManager.class);
2415         when(
2416                 ChooserActivityOverrideData
2417                         .getInstance()
2418                         .packageManager
2419                         .resolveActivity(any(Intent.class), any()))
2420                 .thenReturn(createFakeResolveInfo());
2421 
2422         mActivityRule.launchActivity(chooserIntent);
2423         waitForIdle();
2424         onView(withText(R.string.resolver_work_tab)).perform(click());
2425         waitForIdle();
2426         onView(withId(com.android.internal.R.id.contentPanel))
2427                 .perform(swipeUp());
2428 
2429         onView(withText(R.string.resolver_cross_profile_blocked))
2430                 .check(matches(isDisplayed()));
2431     }
2432 
2433     @Test
testWorkTab_noWorkAppsAvailable_nonSendIntent_emptyStateShown()2434     public void testWorkTab_noWorkAppsAvailable_nonSendIntent_emptyStateShown() {
2435         markWorkProfileUserAvailable();
2436         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2437                 createResolvedComponentsForTest(3);
2438         List<ResolvedComponentInfo> workResolvedComponentInfos =
2439                 createResolvedComponentsForTest(0);
2440         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
2441         Intent[] initialIntents = {
2442                 new Intent("action.fake1"),
2443                 new Intent("action.fake2")
2444         };
2445         Intent chooserIntent = createChooserIntent(new Intent(), initialIntents);
2446         ChooserActivityOverrideData.getInstance().packageManager = mock(PackageManager.class);
2447         when(
2448                 ChooserActivityOverrideData
2449                         .getInstance()
2450                         .packageManager
2451                         .resolveActivity(any(Intent.class), any()))
2452                 .thenReturn(createFakeResolveInfo());
2453 
2454         mActivityRule.launchActivity(chooserIntent);
2455         waitForIdle();
2456         onView(withId(com.android.internal.R.id.contentPanel))
2457                 .perform(swipeUp());
2458         onView(withText(R.string.resolver_work_tab)).perform(click());
2459         waitForIdle();
2460 
2461         onView(withText(R.string.resolver_no_work_apps_available))
2462                 .check(matches(isDisplayed()));
2463     }
2464 
2465     @Test
testDeduplicateCallerTargetRankedTarget()2466     public void testDeduplicateCallerTargetRankedTarget() {
2467         // Create 4 ranked app targets.
2468         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2469                 createResolvedComponentsForTest(4);
2470         setupResolverControllers(personalResolvedComponentInfos);
2471         // Create caller target which is duplicate with one of app targets
2472         Intent chooserIntent = createChooserIntent(createSendTextIntent(),
2473                 new Intent[] {new Intent("action.fake")});
2474         ChooserActivityOverrideData.getInstance().packageManager = mock(PackageManager.class);
2475         ResolveInfo ri = ResolverDataProvider.createResolveInfo(0,
2476                 UserHandle.USER_CURRENT);
2477         when(
2478                 ChooserActivityOverrideData
2479                         .getInstance()
2480                         .packageManager
2481                         .resolveActivity(any(Intent.class), any()))
2482                 .thenReturn(ri);
2483         waitForIdle();
2484 
2485         IChooserWrapper activity = (IChooserWrapper) mActivityRule.launchActivity(chooserIntent);
2486         waitForIdle();
2487 
2488         // Total 4 targets (1 caller target, 3 ranked targets)
2489         assertThat(activity.getAdapter().getCount(), is(4));
2490         assertThat(activity.getAdapter().getCallerTargetCount(), is(1));
2491         assertThat(activity.getAdapter().getRankedTargetCount(), is(3));
2492     }
2493 
2494     @Test
test_query_shortcut_loader_for_the_selected_tab()2495     public void test_query_shortcut_loader_for_the_selected_tab() {
2496         markWorkProfileUserAvailable();
2497         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2498                 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
2499         List<ResolvedComponentInfo> workResolvedComponentInfos =
2500                 createResolvedComponentsForTest(3);
2501         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
2502         ShortcutLoader personalProfileShortcutLoader = mock(ShortcutLoader.class);
2503         ShortcutLoader workProfileShortcutLoader = mock(ShortcutLoader.class);
2504         final SparseArray<ShortcutLoader> shortcutLoaders = new SparseArray<>();
2505         shortcutLoaders.put(0, personalProfileShortcutLoader);
2506         shortcutLoaders.put(10, workProfileShortcutLoader);
2507         ChooserActivityOverrideData.getInstance().shortcutLoaderFactory =
2508                 (userHandle, callback) -> shortcutLoaders.get(userHandle.getIdentifier(), null);
2509         Intent sendIntent = createSendTextIntent();
2510         sendIntent.setType(TEST_MIME_TYPE);
2511 
2512         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
2513         waitForIdle();
2514         onView(withId(com.android.internal.R.id.contentPanel))
2515                 .perform(swipeUp());
2516         waitForIdle();
2517 
2518         verify(personalProfileShortcutLoader, times(1)).queryShortcuts(any());
2519 
2520         onView(withText(R.string.resolver_work_tab)).perform(click());
2521         waitForIdle();
2522 
2523         verify(workProfileShortcutLoader, times(1)).queryShortcuts(any());
2524     }
2525 
createChooserIntent(Intent intent, Intent[] initialIntents)2526     private Intent createChooserIntent(Intent intent, Intent[] initialIntents) {
2527         Intent chooserIntent = new Intent();
2528         chooserIntent.setAction(Intent.ACTION_CHOOSER);
2529         chooserIntent.putExtra(Intent.EXTRA_TEXT, "testing intent sending");
2530         chooserIntent.putExtra(Intent.EXTRA_TITLE, "some title");
2531         chooserIntent.putExtra(Intent.EXTRA_INTENT, intent);
2532         chooserIntent.setType("text/plain");
2533         if (initialIntents != null) {
2534             chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, initialIntents);
2535         }
2536         return chooserIntent;
2537     }
2538 
2539     /* This is a "test of a test" to make sure that our inherited test class
2540      * is successfully configured to operate on the unbundled-equivalent
2541      * ChooserWrapperActivity.
2542      *
2543      * TODO: remove after unbundling is complete.
2544      */
2545     @Test
testWrapperActivityHasExpectedConcreteType()2546     public void testWrapperActivityHasExpectedConcreteType() {
2547         final ChooserActivity activity = mActivityRule.launchActivity(
2548                 Intent.createChooser(new Intent("ACTION_FOO"), "foo"));
2549         waitForIdle();
2550         assertThat(activity).isInstanceOf(com.android.intentresolver.ChooserWrapperActivity.class);
2551     }
2552 
createFakeResolveInfo()2553     private ResolveInfo createFakeResolveInfo() {
2554         ResolveInfo ri = new ResolveInfo();
2555         ri.activityInfo = new ActivityInfo();
2556         ri.activityInfo.name = "FakeActivityName";
2557         ri.activityInfo.packageName = "fake.package.name";
2558         ri.activityInfo.applicationInfo = new ApplicationInfo();
2559         ri.activityInfo.applicationInfo.packageName = "fake.package.name";
2560         return ri;
2561     }
2562 
createSendTextIntent()2563     private Intent createSendTextIntent() {
2564         Intent sendIntent = new Intent();
2565         sendIntent.setAction(Intent.ACTION_SEND);
2566         sendIntent.putExtra(Intent.EXTRA_TEXT, "testing intent sending");
2567         sendIntent.setType("text/plain");
2568         return sendIntent;
2569     }
2570 
createSendImageIntent(Uri imageThumbnail)2571     private Intent createSendImageIntent(Uri imageThumbnail) {
2572         Intent sendIntent = new Intent();
2573         sendIntent.setAction(Intent.ACTION_SEND);
2574         sendIntent.putExtra(Intent.EXTRA_STREAM, imageThumbnail);
2575         sendIntent.setType("image/png");
2576         if (imageThumbnail != null) {
2577             ClipData.Item clipItem = new ClipData.Item(imageThumbnail);
2578             sendIntent.setClipData(new ClipData("Clip Label", new String[]{"image/png"}, clipItem));
2579         }
2580 
2581         return sendIntent;
2582     }
2583 
createSendTextIntentWithPreview(String title, Uri imageThumbnail)2584     private Intent createSendTextIntentWithPreview(String title, Uri imageThumbnail) {
2585         Intent sendIntent = new Intent();
2586         sendIntent.setAction(Intent.ACTION_SEND);
2587         sendIntent.putExtra(Intent.EXTRA_TEXT, "testing intent sending");
2588         sendIntent.putExtra(Intent.EXTRA_TITLE, title);
2589         if (imageThumbnail != null) {
2590             ClipData.Item clipItem = new ClipData.Item(imageThumbnail);
2591             sendIntent.setClipData(new ClipData("Clip Label", new String[]{"image/png"}, clipItem));
2592         }
2593 
2594         return sendIntent;
2595     }
2596 
createSendUriIntentWithPreview(ArrayList<Uri> uris)2597     private Intent createSendUriIntentWithPreview(ArrayList<Uri> uris) {
2598         Intent sendIntent = new Intent();
2599 
2600         if (uris.size() > 1) {
2601             sendIntent.setAction(Intent.ACTION_SEND_MULTIPLE);
2602             sendIntent.putExtra(Intent.EXTRA_STREAM, uris);
2603         } else {
2604             sendIntent.setAction(Intent.ACTION_SEND);
2605             sendIntent.putExtra(Intent.EXTRA_STREAM, uris.get(0));
2606         }
2607 
2608         return sendIntent;
2609     }
2610 
createViewTextIntent()2611     private Intent createViewTextIntent() {
2612         Intent viewIntent = new Intent();
2613         viewIntent.setAction(Intent.ACTION_VIEW);
2614         viewIntent.putExtra(Intent.EXTRA_TEXT, "testing intent viewing");
2615         return viewIntent;
2616     }
2617 
createResolvedComponentsForTest(int numberOfResults)2618     private List<ResolvedComponentInfo> createResolvedComponentsForTest(int numberOfResults) {
2619         List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
2620         for (int i = 0; i < numberOfResults; i++) {
2621             infoList.add(ResolverDataProvider.createResolvedComponentInfo(i));
2622         }
2623         return infoList;
2624     }
2625 
createResolvedComponentsForTestWithOtherProfile( int numberOfResults)2626     private List<ResolvedComponentInfo> createResolvedComponentsForTestWithOtherProfile(
2627             int numberOfResults) {
2628         List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
2629         for (int i = 0; i < numberOfResults; i++) {
2630             if (i == 0) {
2631                 infoList.add(ResolverDataProvider.createResolvedComponentInfoWithOtherId(i));
2632             } else {
2633                 infoList.add(ResolverDataProvider.createResolvedComponentInfo(i));
2634             }
2635         }
2636         return infoList;
2637     }
2638 
createResolvedComponentsForTestWithOtherProfile( int numberOfResults, int userId)2639     private List<ResolvedComponentInfo> createResolvedComponentsForTestWithOtherProfile(
2640             int numberOfResults, int userId) {
2641         List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
2642         for (int i = 0; i < numberOfResults; i++) {
2643             if (i == 0) {
2644                 infoList.add(
2645                         ResolverDataProvider.createResolvedComponentInfoWithOtherId(i, userId));
2646             } else {
2647                 infoList.add(ResolverDataProvider.createResolvedComponentInfo(i));
2648             }
2649         }
2650         return infoList;
2651     }
2652 
createResolvedComponentsForTestWithUserId( int numberOfResults, int userId)2653     private List<ResolvedComponentInfo> createResolvedComponentsForTestWithUserId(
2654             int numberOfResults, int userId) {
2655         List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
2656         for (int i = 0; i < numberOfResults; i++) {
2657             infoList.add(ResolverDataProvider.createResolvedComponentInfoWithOtherId(i, userId));
2658         }
2659         return infoList;
2660     }
2661 
createDirectShareTargets(int numberOfResults, String packageName)2662     private List<ChooserTarget> createDirectShareTargets(int numberOfResults, String packageName) {
2663         Icon icon = Icon.createWithBitmap(createBitmap());
2664         String testTitle = "testTitle";
2665         List<ChooserTarget> targets = new ArrayList<>();
2666         for (int i = 0; i < numberOfResults; i++) {
2667             ComponentName componentName;
2668             if (packageName.isEmpty()) {
2669                 componentName = ResolverDataProvider.createComponentName(i);
2670             } else {
2671                 componentName = new ComponentName(packageName, packageName + ".class");
2672             }
2673             ChooserTarget tempTarget = new ChooserTarget(
2674                     testTitle + i,
2675                     icon,
2676                     (float) (1 - ((i + 1) / 10.0)),
2677                     componentName,
2678                     null);
2679             targets.add(tempTarget);
2680         }
2681         return targets;
2682     }
2683 
waitForIdle()2684     private void waitForIdle() {
2685         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
2686     }
2687 
createBitmap()2688     private Bitmap createBitmap() {
2689         int width = 200;
2690         int height = 200;
2691         Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
2692         Canvas canvas = new Canvas(bitmap);
2693 
2694         Paint paint = new Paint();
2695         paint.setColor(Color.RED);
2696         paint.setStyle(Paint.Style.FILL);
2697         canvas.drawPaint(paint);
2698 
2699         paint.setColor(Color.WHITE);
2700         paint.setAntiAlias(true);
2701         paint.setTextSize(14.f);
2702         paint.setTextAlign(Paint.Align.CENTER);
2703         canvas.drawText("Hi!", (width / 2.f), (height / 2.f), paint);
2704 
2705         return bitmap;
2706     }
2707 
createShortcuts(Context context)2708     private List<ShareShortcutInfo> createShortcuts(Context context) {
2709         Intent testIntent = new Intent("TestIntent");
2710 
2711         List<ShareShortcutInfo> shortcuts = new ArrayList<>();
2712         shortcuts.add(new ShareShortcutInfo(
2713                 new ShortcutInfo.Builder(context, "shortcut1")
2714                         .setIntent(testIntent).setShortLabel("label1").setRank(3).build(), // 0  2
2715                 new ComponentName("package1", "class1")));
2716         shortcuts.add(new ShareShortcutInfo(
2717                 new ShortcutInfo.Builder(context, "shortcut2")
2718                         .setIntent(testIntent).setShortLabel("label2").setRank(7).build(), // 1  3
2719                 new ComponentName("package2", "class2")));
2720         shortcuts.add(new ShareShortcutInfo(
2721                 new ShortcutInfo.Builder(context, "shortcut3")
2722                         .setIntent(testIntent).setShortLabel("label3").setRank(1).build(), // 2  0
2723                 new ComponentName("package3", "class3")));
2724         shortcuts.add(new ShareShortcutInfo(
2725                 new ShortcutInfo.Builder(context, "shortcut4")
2726                         .setIntent(testIntent).setShortLabel("label4").setRank(3).build(), // 3  2
2727                 new ComponentName("package4", "class4")));
2728 
2729         return shortcuts;
2730     }
2731 
markWorkProfileUserAvailable()2732     private void markWorkProfileUserAvailable() {
2733         ChooserActivityOverrideData.getInstance().workProfileUserHandle = UserHandle.of(10);
2734     }
2735 
setupResolverControllers( List<ResolvedComponentInfo> personalResolvedComponentInfos)2736     private void setupResolverControllers(
2737             List<ResolvedComponentInfo> personalResolvedComponentInfos) {
2738         setupResolverControllers(personalResolvedComponentInfos, new ArrayList<>());
2739     }
2740 
setupResolverControllers( List<ResolvedComponentInfo> personalResolvedComponentInfos, List<ResolvedComponentInfo> workResolvedComponentInfos)2741     private void setupResolverControllers(
2742             List<ResolvedComponentInfo> personalResolvedComponentInfos,
2743             List<ResolvedComponentInfo> workResolvedComponentInfos) {
2744         when(
2745                 ChooserActivityOverrideData
2746                         .getInstance()
2747                         .resolverListController
2748                         .getResolversForIntentAsUser(
2749                                 Mockito.anyBoolean(),
2750                                 Mockito.anyBoolean(),
2751                                 Mockito.anyBoolean(),
2752                                 Mockito.isA(List.class),
2753                                 eq(UserHandle.SYSTEM)))
2754                 .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
2755         when(
2756                 ChooserActivityOverrideData
2757                         .getInstance()
2758                         .workResolverListController
2759                         .getResolversForIntentAsUser(
2760                                 Mockito.anyBoolean(),
2761                                 Mockito.anyBoolean(),
2762                                 Mockito.anyBoolean(),
2763                                 Mockito.isA(List.class),
2764                                 eq(UserHandle.SYSTEM)))
2765                 .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
2766         when(
2767                 ChooserActivityOverrideData
2768                         .getInstance()
2769                         .workResolverListController
2770                         .getResolversForIntentAsUser(
2771                                 Mockito.anyBoolean(),
2772                                 Mockito.anyBoolean(),
2773                                 Mockito.anyBoolean(),
2774                                 Mockito.isA(List.class),
2775                                 eq(UserHandle.of(10))))
2776                 .thenReturn(new ArrayList<>(workResolvedComponentInfos));
2777     }
2778 
withGridColumnCount(int columnCount)2779     private static GridRecyclerSpanCountMatcher withGridColumnCount(int columnCount) {
2780         return new GridRecyclerSpanCountMatcher(Matchers.is(columnCount));
2781     }
2782 
2783     private static class GridRecyclerSpanCountMatcher extends
2784             BoundedDiagnosingMatcher<View, RecyclerView> {
2785 
2786         private final Matcher<Integer> mIntegerMatcher;
2787 
GridRecyclerSpanCountMatcher(Matcher<Integer> integerMatcher)2788         private GridRecyclerSpanCountMatcher(Matcher<Integer> integerMatcher) {
2789             super(RecyclerView.class);
2790             this.mIntegerMatcher = integerMatcher;
2791         }
2792 
2793         @Override
describeMoreTo(Description description)2794         protected void describeMoreTo(Description description) {
2795             description.appendText("RecyclerView grid layout span count to match: ");
2796             this.mIntegerMatcher.describeTo(description);
2797         }
2798 
2799         @Override
matchesSafely(RecyclerView view, Description mismatchDescription)2800         protected boolean matchesSafely(RecyclerView view, Description mismatchDescription) {
2801             int spanCount = ((GridLayoutManager) view.getLayoutManager()).getSpanCount();
2802             if (this.mIntegerMatcher.matches(spanCount)) {
2803                 return true;
2804             } else {
2805                 mismatchDescription.appendText("RecyclerView grid layout span count was ")
2806                         .appendValue(spanCount);
2807                 return false;
2808             }
2809         }
2810     }
2811 
givenAppTargets(int appCount)2812     private void givenAppTargets(int appCount) {
2813         List<ResolvedComponentInfo> resolvedComponentInfos =
2814                 createResolvedComponentsForTest(appCount);
2815         setupResolverControllers(resolvedComponentInfos);
2816     }
2817 
updateMaxTargetsPerRowResource(int targetsPerRow)2818     private void updateMaxTargetsPerRowResource(int targetsPerRow) {
2819         ChooserActivityOverrideData.getInstance().resources = Mockito.spy(
2820                 InstrumentationRegistry.getInstrumentation().getContext().getResources());
2821         when(
2822                 ChooserActivityOverrideData
2823                         .getInstance()
2824                         .resources
2825                         .getInteger(R.integer.config_chooser_max_targets_per_row))
2826                 .thenReturn(targetsPerRow);
2827     }
2828 
2829     private SparseArray<Pair<ShortcutLoader, Consumer<ShortcutLoader.Result>>>
createShortcutLoaderFactory()2830             createShortcutLoaderFactory() {
2831         SparseArray<Pair<ShortcutLoader, Consumer<ShortcutLoader.Result>>> shortcutLoaders =
2832                 new SparseArray<>();
2833         ChooserActivityOverrideData.getInstance().shortcutLoaderFactory =
2834                 (userHandle, callback) -> {
2835                     Pair<ShortcutLoader, Consumer<ShortcutLoader.Result>> pair =
2836                             new Pair<>(mock(ShortcutLoader.class), callback);
2837                     shortcutLoaders.put(userHandle.getIdentifier(), pair);
2838                     return pair.first;
2839                 };
2840         return shortcutLoaders;
2841     }
2842 }
2843