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.internal.app;
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.swipeUp;
24 import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
25 import static androidx.test.espresso.assertion.ViewAssertions.matches;
26 import static androidx.test.espresso.matcher.ViewMatchers.hasSibling;
27 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
28 import static androidx.test.espresso.matcher.ViewMatchers.withId;
29 import static androidx.test.espresso.matcher.ViewMatchers.withText;
30 
31 import static com.android.internal.app.ChooserActivity.TARGET_TYPE_CHOOSER_TARGET;
32 import static com.android.internal.app.ChooserActivity.TARGET_TYPE_DEFAULT;
33 import static com.android.internal.app.ChooserActivity.TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE;
34 import static com.android.internal.app.ChooserActivity.TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER;
35 import static com.android.internal.app.ChooserListAdapter.CALLER_TARGET_SCORE_BOOST;
36 import static com.android.internal.app.ChooserListAdapter.SHORTCUT_TARGET_SCORE_BOOST;
37 import static com.android.internal.app.MatcherUtils.first;
38 
39 import static junit.framework.Assert.assertFalse;
40 import static junit.framework.Assert.assertNull;
41 import static junit.framework.Assert.assertTrue;
42 
43 import static org.hamcrest.CoreMatchers.allOf;
44 import static org.hamcrest.CoreMatchers.is;
45 import static org.hamcrest.CoreMatchers.not;
46 import static org.hamcrest.CoreMatchers.notNullValue;
47 import static org.hamcrest.MatcherAssert.assertThat;
48 import static org.hamcrest.Matchers.greaterThan;
49 import static org.junit.Assert.assertEquals;
50 import static org.mockito.ArgumentMatchers.any;
51 import static org.mockito.ArgumentMatchers.anyInt;
52 import static org.mockito.ArgumentMatchers.eq;
53 import static org.mockito.Mockito.atLeastOnce;
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.usage.UsageStatsManager;
60 import android.content.ClipData;
61 import android.content.ClipDescription;
62 import android.content.ClipboardManager;
63 import android.content.ComponentName;
64 import android.content.Context;
65 import android.content.Intent;
66 import android.content.pm.ActivityInfo;
67 import android.content.pm.ApplicationInfo;
68 import android.content.pm.PackageManager;
69 import android.content.pm.ResolveInfo;
70 import android.content.pm.ShortcutInfo;
71 import android.content.pm.ShortcutManager.ShareShortcutInfo;
72 import android.content.res.Configuration;
73 import android.database.Cursor;
74 import android.graphics.Bitmap;
75 import android.graphics.Canvas;
76 import android.graphics.Color;
77 import android.graphics.Paint;
78 import android.graphics.drawable.Icon;
79 import android.metrics.LogMaker;
80 import android.net.Uri;
81 import android.os.UserHandle;
82 import android.provider.DeviceConfig;
83 import android.service.chooser.ChooserTarget;
84 import android.util.Pair;
85 import android.view.View;
86 
87 import androidx.annotation.CallSuper;
88 import androidx.test.espresso.matcher.BoundedDiagnosingMatcher;
89 import androidx.test.platform.app.InstrumentationRegistry;
90 import androidx.test.rule.ActivityTestRule;
91 
92 import com.android.internal.R;
93 import com.android.internal.app.ChooserActivity.ServiceResultInfo;
94 import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
95 import com.android.internal.app.chooser.DisplayResolveInfo;
96 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
97 import com.android.internal.logging.MetricsLogger;
98 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
99 import com.android.internal.util.FrameworkStatsLog;
100 import com.android.internal.widget.GridLayoutManager;
101 import com.android.internal.widget.RecyclerView;
102 
103 import org.hamcrest.Description;
104 import org.hamcrest.Matcher;
105 import org.hamcrest.Matchers;
106 import org.junit.Before;
107 import org.junit.Ignore;
108 import org.junit.Rule;
109 import org.junit.Test;
110 import org.junit.runner.RunWith;
111 import org.junit.runners.Parameterized;
112 import org.mockito.ArgumentCaptor;
113 import org.mockito.Mockito;
114 
115 import java.util.ArrayList;
116 import java.util.Arrays;
117 import java.util.Collection;
118 import java.util.HashMap;
119 import java.util.List;
120 import java.util.Map;
121 import java.util.function.Function;
122 
123 /**
124  * Instrumentation tests for chooser activities that derive from the system
125  * {@code com.android.internal.ChooserActivity}. This class is used directly to test the system
126  * implementation, but clients can inherit from this test to apply the same suite of chooser tests
127  * to their own ChooserActivity implementations. Clients should override
128  * #getConcreteIntentForLaunch() to configure an intent that will launch their concrete
129  * ChooserActivity subtype. Tests will assume that this subtype implements the IChooserWrapper
130  * interface, which is only appropriate for testing. Clients will typically create their own
131  * "ChooserWrapperActivity" by copy-and-pasting the system implementation, parenting to their own
132  * ChooserActivity subclass instead of directly to the system implementation. Code comments in this
133  * file provide direction for developers creating derived test suites, and eventually for removing
134  * the extra complexity once we no longer need to support parallel ChooserActivity implementations.
135  */
136 @RunWith(Parameterized.class)
137 public class ChooserActivityTest {
138 
139     /* --------
140      * Subclasses should copy the following section verbatim (or alternatively could specify some
141      * additional @Parameterized.Parameters, as long as the correct parameters are used to
142      * initialize the ChooserActivityTest). The subclasses should also be @RunWith the
143      * `Parameterized` runner.
144      * --------
145      */
146     private static final UserHandle PERSONAL_USER_HANDLE = InstrumentationRegistry
147             .getInstrumentation().getTargetContext().getUser();
148     private static final Function<PackageManager, PackageManager> DEFAULT_PM = pm -> pm;
149     private static final Function<PackageManager, PackageManager> NO_APP_PREDICTION_SERVICE_PM =
150             pm -> {
151                 PackageManager mock = Mockito.spy(pm);
152                 when(mock.getAppPredictionServicePackageName()).thenReturn(null);
153                 return mock;
154             };
155 
156     @Parameterized.Parameters
packageManagers()157     public static Collection packageManagers() {
158         return Arrays.asList(new Object[][] {
159                 {0, "Default PackageManager", DEFAULT_PM},
160                 {1, "No App Prediction Service", NO_APP_PREDICTION_SERVICE_PM}
161         });
162     }
163 
164     /* --------
165      * Subclasses can override the following methods to customize test behavior.
166      * --------
167      */
168 
169     /**
170      * Perform any necessary per-test initialization steps (subclasses may add additional steps
171      * before and/or after calling up to the superclass implementation).
172      */
173     @CallSuper
setup()174     protected void setup() {
175         cleanOverrideData();
176     }
177 
178     /**
179      * Given an intent that was constructed in a test, perform any additional configuration to
180      * specify the appropriate concrete ChooserActivity subclass. The activity launched by this
181      * intent must descend from android.internal.app.ChooserActivity (for our ActivityTestRule), and
182      * must also implement the android.internal.app.IChooserWrapper interface (since test code will
183      * assume the ability to make unsafe downcasts).
184      */
getConcreteIntentForLaunch(Intent clientIntent)185     protected Intent getConcreteIntentForLaunch(Intent clientIntent) {
186         clientIntent.setClass(
187                 InstrumentationRegistry.getInstrumentation().getTargetContext(),
188                 com.android.internal.app.ChooserWrapperActivity.class);
189         return clientIntent;
190     }
191 
192     /**
193      * Whether {@code #testIsAppPredictionServiceAvailable} should verify the behavior after
194      * changing the availability conditions at runtime. In the unbundled chooser, the availability
195      * is cached at start and will never be re-evaluated.
196      * TODO: remove when we no longer want to test the system's on-the-fly evaluation.
197      */
shouldTestTogglingAppPredictionServiceAvailabilityAtRuntime()198     protected boolean shouldTestTogglingAppPredictionServiceAvailabilityAtRuntime() {
199         return false;
200     }
201 
202     /* --------
203      * The code in this section is unorthodox and can be simplified/reverted when we no longer need
204      * to support the parallel chooser implementations.
205      * --------
206      */
207 
208     // Shared test code references the activity under test as ChooserActivity, the common ancestor
209     // of any (inheritance-based) chooser implementation. For testing purposes, that activity will
210     // usually be cast to IChooserWrapper to expose instrumentation.
211     @Rule
212     public ActivityTestRule<ChooserActivity> mActivityRule =
213             new ActivityTestRule<>(ChooserActivity.class, false, false) {
214                 @Override
215                 public ChooserActivity launchActivity(Intent clientIntent) {
216                     return super.launchActivity(getConcreteIntentForLaunch(clientIntent));
217                 }
218             };
219 
220     @Before
doPolymorphicSetup()221     public final void doPolymorphicSetup() {
222         // The base class needs a @Before-annotated setup for when it runs against the system
223         // chooser, while subclasses need to be able to specify their own setup behavior. Notably
224         // the unbundled chooser, running in user-space, needs to take additional steps before it
225         // can run #cleanOverrideData() (which writes to DeviceConfig).
226         setup();
227     }
228 
229     /* --------
230      * Subclasses can ignore the remaining code and inherit the full suite of tests.
231      * --------
232      */
233 
234     private static final String TEST_MIME_TYPE = "application/TestType";
235 
236     private static final int CONTENT_PREVIEW_IMAGE = 1;
237     private static final int CONTENT_PREVIEW_FILE = 2;
238     private static final int CONTENT_PREVIEW_TEXT = 3;
239     private Function<PackageManager, PackageManager> mPackageManagerOverride;
240     private int mTestNum;
241 
242 
ChooserActivityTest( int testNum, String testName, Function<PackageManager, PackageManager> packageManagerOverride)243     public ChooserActivityTest(
244                 int testNum,
245                 String testName,
246                 Function<PackageManager, PackageManager> packageManagerOverride) {
247         mPackageManagerOverride = packageManagerOverride;
248         mTestNum = testNum;
249     }
250 
cleanOverrideData()251     public void cleanOverrideData() {
252         ChooserActivityOverrideData.getInstance().reset();
253         ChooserActivityOverrideData.getInstance().createPackageManager = mPackageManagerOverride;
254         DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
255                 SystemUiDeviceConfigFlags.APPLY_SHARING_APP_LIMITS_IN_SYSUI,
256                 Boolean.toString(true),
257                 true /* makeDefault*/);
258     }
259 
260     @Test
customTitle()261     public void customTitle() throws InterruptedException {
262         Intent viewIntent = createViewTextIntent();
263         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
264 
265         when(
266                 ChooserActivityOverrideData
267                         .getInstance()
268                         .resolverListController
269                         .getResolversForIntent(
270                                 Mockito.anyBoolean(),
271                                 Mockito.anyBoolean(),
272                                 Mockito.anyBoolean(),
273                                 Mockito.isA(List.class)))
274                 .thenReturn(resolvedComponentInfos);
275         final IChooserWrapper activity = (IChooserWrapper) mActivityRule.launchActivity(
276                 Intent.createChooser(viewIntent, "chooser test"));
277 
278         waitForIdle();
279         assertThat(activity.getAdapter().getCount(), is(2));
280         assertThat(activity.getAdapter().getServiceTargetCount(), is(0));
281         onView(withIdFromRuntimeResource("title")).check(matches(withText("chooser test")));
282     }
283 
284     @Test
customTitleIgnoredForSendIntents()285     public void customTitleIgnoredForSendIntents() throws InterruptedException {
286         Intent sendIntent = createSendTextIntent();
287         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
288 
289         when(
290                 ChooserActivityOverrideData
291                         .getInstance()
292                         .resolverListController
293                         .getResolversForIntent(
294                                 Mockito.anyBoolean(),
295                                 Mockito.anyBoolean(),
296                                 Mockito.anyBoolean(),
297                                 Mockito.isA(List.class)))
298                 .thenReturn(resolvedComponentInfos);
299         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "chooser test"));
300         waitForIdle();
301         onView(withIdFromRuntimeResource("title"))
302                 .check(matches(withTextFromRuntimeResource("whichSendApplication")));
303     }
304 
305     @Test
emptyTitle()306     public void emptyTitle() throws InterruptedException {
307         Intent sendIntent = createSendTextIntent();
308         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
309 
310         when(
311                 ChooserActivityOverrideData
312                         .getInstance()
313                         .resolverListController
314                         .getResolversForIntent(
315                                 Mockito.anyBoolean(),
316                                 Mockito.anyBoolean(),
317                                 Mockito.anyBoolean(),
318                                 Mockito.isA(List.class)))
319                 .thenReturn(resolvedComponentInfos);
320         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
321         waitForIdle();
322         onView(withIdFromRuntimeResource("title"))
323                 .check(matches(withTextFromRuntimeResource("whichSendApplication")));
324     }
325 
326     @Test
emptyPreviewTitleAndThumbnail()327     public void emptyPreviewTitleAndThumbnail() throws InterruptedException {
328         Intent sendIntent = createSendTextIntentWithPreview(null, null);
329         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
330 
331         when(
332                 ChooserActivityOverrideData
333                         .getInstance()
334                         .resolverListController
335                         .getResolversForIntent(
336                                 Mockito.anyBoolean(),
337                                 Mockito.anyBoolean(),
338                                 Mockito.anyBoolean(),
339                                 Mockito.isA(List.class)))
340                 .thenReturn(resolvedComponentInfos);
341         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
342         waitForIdle();
343         onView(withIdFromRuntimeResource("content_preview_title"))
344                 .check(matches(not(isDisplayed())));
345         onView(withIdFromRuntimeResource("content_preview_thumbnail"))
346                 .check(matches(not(isDisplayed())));
347     }
348 
349     @Test
visiblePreviewTitleWithoutThumbnail()350     public void visiblePreviewTitleWithoutThumbnail() throws InterruptedException {
351         String previewTitle = "My Content Preview Title";
352         Intent sendIntent = createSendTextIntentWithPreview(previewTitle, null);
353         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
354 
355         when(
356                 ChooserActivityOverrideData
357                         .getInstance()
358                         .resolverListController
359                         .getResolversForIntent(
360                                 Mockito.anyBoolean(),
361                                 Mockito.anyBoolean(),
362                                 Mockito.anyBoolean(),
363                                 Mockito.isA(List.class)))
364                 .thenReturn(resolvedComponentInfos);
365         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
366         waitForIdle();
367         onView(withIdFromRuntimeResource("content_preview_title"))
368                 .check(matches(isDisplayed()));
369         onView(withIdFromRuntimeResource("content_preview_title"))
370                 .check(matches(withText(previewTitle)));
371         onView(withIdFromRuntimeResource("content_preview_thumbnail"))
372                 .check(matches(not(isDisplayed())));
373     }
374 
375     @Test
visiblePreviewTitleWithInvalidThumbnail()376     public void visiblePreviewTitleWithInvalidThumbnail() throws InterruptedException {
377         String previewTitle = "My Content Preview Title";
378         Intent sendIntent = createSendTextIntentWithPreview(previewTitle,
379                 Uri.parse("tel:(+49)12345789"));
380         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
381 
382         when(
383                 ChooserActivityOverrideData
384                         .getInstance()
385                         .resolverListController
386                         .getResolversForIntent(
387                                 Mockito.anyBoolean(),
388                                 Mockito.anyBoolean(),
389                                 Mockito.anyBoolean(),
390                                 Mockito.isA(List.class)))
391                 .thenReturn(resolvedComponentInfos);
392         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
393         waitForIdle();
394         onView(withIdFromRuntimeResource("content_preview_title")).check(matches(isDisplayed()));
395         onView(withIdFromRuntimeResource("content_preview_thumbnail"))
396                 .check(matches(not(isDisplayed())));
397     }
398 
399     @Test
visiblePreviewTitleAndThumbnail()400     public void visiblePreviewTitleAndThumbnail() throws InterruptedException {
401         String previewTitle = "My Content Preview Title";
402         Intent sendIntent = createSendTextIntentWithPreview(previewTitle,
403                 Uri.parse("android.resource://com.android.frameworks.coretests/"
404                         + com.android.frameworks.coretests.R.drawable.test320x240));
405         ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
406         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
407 
408         when(
409                 ChooserActivityOverrideData
410                         .getInstance()
411                         .resolverListController
412                         .getResolversForIntent(
413                                 Mockito.anyBoolean(),
414                                 Mockito.anyBoolean(),
415                                 Mockito.anyBoolean(),
416                                 Mockito.isA(List.class)))
417                 .thenReturn(resolvedComponentInfos);
418         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
419         waitForIdle();
420         onView(withIdFromRuntimeResource("content_preview_title")).check(matches(isDisplayed()));
421         onView(withIdFromRuntimeResource("content_preview_thumbnail"))
422                 .check(matches(isDisplayed()));
423     }
424 
425     @Test @Ignore
twoOptionsAndUserSelectsOne()426     public void twoOptionsAndUserSelectsOne() throws InterruptedException {
427         Intent sendIntent = createSendTextIntent();
428         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
429 
430         when(
431                 ChooserActivityOverrideData
432                         .getInstance()
433                         .resolverListController
434                         .getResolversForIntent(
435                                 Mockito.anyBoolean(),
436                                 Mockito.anyBoolean(),
437                                 Mockito.anyBoolean(),
438                                 Mockito.isA(List.class)))
439                 .thenReturn(resolvedComponentInfos);
440 
441         final IChooserWrapper activity = (IChooserWrapper)
442                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
443         waitForIdle();
444 
445         assertThat(activity.getAdapter().getCount(), is(2));
446         onView(withIdFromRuntimeResource("profile_button")).check(doesNotExist());
447 
448         ResolveInfo[] chosen = new ResolveInfo[1];
449         ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
450             chosen[0] = targetInfo.getResolveInfo();
451             return true;
452         };
453 
454         ResolveInfo toChoose = resolvedComponentInfos.get(0).getResolveInfoAt(0);
455         onView(withText(toChoose.activityInfo.name))
456                 .perform(click());
457         waitForIdle();
458         assertThat(chosen[0], is(toChoose));
459     }
460 
461     @Test @Ignore
fourOptionsStackedIntoOneTarget()462     public void fourOptionsStackedIntoOneTarget() throws InterruptedException {
463         Intent sendIntent = createSendTextIntent();
464 
465         // create just enough targets to ensure the a-z list should be shown
466         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(1);
467 
468         // next create 4 targets in a single app that should be stacked into a single target
469         String packageName = "xxx.yyy";
470         String appName = "aaa";
471         ComponentName cn = new ComponentName(packageName, appName);
472         Intent intent = new Intent("fakeIntent");
473         List<ResolvedComponentInfo> infosToStack = new ArrayList<>();
474         for (int i = 0; i < 4; i++) {
475             ResolveInfo resolveInfo = ResolverDataProvider.createResolveInfo(i,
476                     UserHandle.USER_CURRENT, PERSONAL_USER_HANDLE);
477             resolveInfo.activityInfo.applicationInfo.name = appName;
478             resolveInfo.activityInfo.applicationInfo.packageName = packageName;
479             resolveInfo.activityInfo.packageName = packageName;
480             resolveInfo.activityInfo.name = "ccc" + i;
481             infosToStack.add(new ResolvedComponentInfo(cn, intent, resolveInfo));
482         }
483         resolvedComponentInfos.addAll(infosToStack);
484 
485         when(
486                 ChooserActivityOverrideData
487                         .getInstance()
488                         .resolverListController
489                         .getResolversForIntent(
490                                 Mockito.anyBoolean(),
491                                 Mockito.anyBoolean(),
492                                 Mockito.anyBoolean(),
493                                 Mockito.isA(List.class)))
494                 .thenReturn(resolvedComponentInfos);
495 
496         final IChooserWrapper activity = (IChooserWrapper)
497                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
498         waitForIdle();
499 
500         // expect 1 unique targets + 1 group + 4 ranked app targets
501         assertThat(activity.getAdapter().getCount(), is(6));
502 
503         ResolveInfo[] chosen = new ResolveInfo[1];
504         ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
505             chosen[0] = targetInfo.getResolveInfo();
506             return true;
507         };
508 
509         onView(allOf(withText(appName), hasSibling(withText("")))).perform(click());
510         waitForIdle();
511 
512         // clicking will launch a dialog to choose the activity within the app
513         onView(withText(appName)).check(matches(isDisplayed()));
514         int i = 0;
515         for (ResolvedComponentInfo rci: infosToStack) {
516             onView(withText("ccc" + i)).check(matches(isDisplayed()));
517             ++i;
518         }
519     }
520 
521     @Test @Ignore
updateChooserCountsAndModelAfterUserSelection()522     public void updateChooserCountsAndModelAfterUserSelection() throws InterruptedException {
523         Intent sendIntent = createSendTextIntent();
524         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
525 
526         when(
527                 ChooserActivityOverrideData
528                         .getInstance()
529                         .resolverListController
530                         .getResolversForIntent(
531                                 Mockito.anyBoolean(),
532                                 Mockito.anyBoolean(),
533                                 Mockito.anyBoolean(),
534                                 Mockito.isA(List.class)))
535                 .thenReturn(resolvedComponentInfos);
536 
537         final IChooserWrapper activity = (IChooserWrapper)
538                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
539         waitForIdle();
540         UsageStatsManager usm = activity.getUsageStatsManager();
541         verify(ChooserActivityOverrideData.getInstance().resolverListController, times(1))
542                 .topK(any(List.class), anyInt());
543         assertThat(activity.getIsSelected(), is(false));
544         ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
545             return true;
546         };
547         ResolveInfo toChoose = resolvedComponentInfos.get(0).getResolveInfoAt(0);
548         DisplayResolveInfo testDri =
549                 activity.createTestDisplayResolveInfo(sendIntent, toChoose, "testLabel", "testInfo",
550                         sendIntent,/* resolveInfoPresentationGetter */ null);
551         onView(withText(toChoose.activityInfo.name))
552                 .perform(click());
553         waitForIdle();
554         verify(ChooserActivityOverrideData.getInstance().resolverListController, times(1))
555                 .updateChooserCounts(Mockito.anyString(), any(UserHandle.class),
556                         Mockito.anyString());
557         verify(ChooserActivityOverrideData.getInstance().resolverListController, times(1))
558                 .updateModel(testDri);
559         assertThat(activity.getIsSelected(), is(true));
560     }
561 
562     @Ignore // b/148158199
563     @Test
noResultsFromPackageManager()564     public void noResultsFromPackageManager() {
565         when(
566                 ChooserActivityOverrideData
567                         .getInstance()
568                         .resolverListController
569                         .getResolversForIntent(
570                                 Mockito.anyBoolean(),
571                                 Mockito.anyBoolean(),
572                                 Mockito.anyBoolean(),
573                                 Mockito.isA(List.class)))
574                 .thenReturn(null);
575         Intent sendIntent = createSendTextIntent();
576         final ChooserActivity activity =
577                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
578         final IChooserWrapper wrapper = (IChooserWrapper) activity;
579 
580         waitForIdle();
581         assertThat(activity.isFinishing(), is(false));
582 
583         onView(withIdFromRuntimeResource("empty")).check(matches(isDisplayed()));
584         onView(withIdFromRuntimeResource("profile_pager")).check(matches(not(isDisplayed())));
585         InstrumentationRegistry.getInstrumentation().runOnMainSync(
586                 () -> wrapper.getAdapter().handlePackagesChanged()
587         );
588         // backward compatibility. looks like we finish when data is empty after package change
589         assertThat(activity.isFinishing(), is(true));
590     }
591 
592     @Test
autoLaunchSingleResult()593     public void autoLaunchSingleResult() throws InterruptedException {
594         ResolveInfo[] chosen = new ResolveInfo[1];
595         ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
596             chosen[0] = targetInfo.getResolveInfo();
597             return true;
598         };
599 
600         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(1);
601         when(
602                 ChooserActivityOverrideData
603                         .getInstance()
604                         .resolverListController
605                         .getResolversForIntent(
606                                 Mockito.anyBoolean(),
607                                 Mockito.anyBoolean(),
608                                 Mockito.anyBoolean(),
609                                 Mockito.isA(List.class)))
610                 .thenReturn(resolvedComponentInfos);
611 
612         Intent sendIntent = createSendTextIntent();
613         final ChooserActivity activity =
614                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
615         waitForIdle();
616 
617         assertThat(chosen[0], is(resolvedComponentInfos.get(0).getResolveInfoAt(0)));
618         assertThat(activity.isFinishing(), is(true));
619     }
620 
621     @Test @Ignore
hasOtherProfileOneOption()622     public void hasOtherProfileOneOption() throws Exception {
623         // enable the work tab feature flag
624         ResolverActivity.ENABLE_TABBED_VIEW = true;
625         List<ResolvedComponentInfo> personalResolvedComponentInfos =
626                 createResolvedComponentsForTestWithOtherProfile(2, /* userId */ 10);
627         List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4);
628         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
629         markWorkProfileUserAvailable();
630 
631         ResolveInfo toChoose = personalResolvedComponentInfos.get(1).getResolveInfoAt(0);
632         Intent sendIntent = createSendTextIntent();
633         final IChooserWrapper activity = (IChooserWrapper)
634                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
635         waitForIdle();
636 
637         // The other entry is filtered to the other profile slot
638         assertThat(activity.getAdapter().getCount(), is(1));
639 
640         ResolveInfo[] chosen = new ResolveInfo[1];
641         ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
642             chosen[0] = targetInfo.getResolveInfo();
643             return true;
644         };
645 
646         // Make a stable copy of the components as the original list may be modified
647         List<ResolvedComponentInfo> stableCopy =
648                 createResolvedComponentsForTestWithOtherProfile(2, /* userId= */ 10);
649         waitForIdle();
650         Thread.sleep(((ChooserActivity) activity).mListViewUpdateDelayMs);
651 
652         onView(first(withText(stableCopy.get(1).getResolveInfoAt(0).activityInfo.name)))
653                 .perform(click());
654         waitForIdle();
655         assertThat(chosen[0], is(toChoose));
656     }
657 
658     @Test @Ignore
hasOtherProfileTwoOptionsAndUserSelectsOne()659     public void hasOtherProfileTwoOptionsAndUserSelectsOne() throws Exception {
660         // enable the work tab feature flag
661         ResolverActivity.ENABLE_TABBED_VIEW = true;
662 
663         Intent sendIntent = createSendTextIntent();
664         List<ResolvedComponentInfo> resolvedComponentInfos =
665                 createResolvedComponentsForTestWithOtherProfile(3);
666         ResolveInfo toChoose = resolvedComponentInfos.get(1).getResolveInfoAt(0);
667 
668         when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent(
669                 Mockito.anyBoolean(),
670                 Mockito.anyBoolean(),
671                 Mockito.anyBoolean(),
672                 Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
673         when(ChooserActivityOverrideData.getInstance().resolverListController.getLastChosen())
674                 .thenReturn(resolvedComponentInfos.get(0).getResolveInfoAt(0));
675 
676         final IChooserWrapper activity = (IChooserWrapper)
677                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
678         waitForIdle();
679 
680         // The other entry is filtered to the other profile slot
681         assertThat(activity.getAdapter().getCount(), is(2));
682 
683         ResolveInfo[] chosen = new ResolveInfo[1];
684         ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
685             chosen[0] = targetInfo.getResolveInfo();
686             return true;
687         };
688 
689         // Make a stable copy of the components as the original list may be modified
690         List<ResolvedComponentInfo> stableCopy =
691                 createResolvedComponentsForTestWithOtherProfile(3);
692         onView(withText(stableCopy.get(1).getResolveInfoAt(0).activityInfo.name))
693                 .perform(click());
694         waitForIdle();
695         assertThat(chosen[0], is(toChoose));
696     }
697 
698     @Test @Ignore
hasLastChosenActivityAndOtherProfile()699     public void hasLastChosenActivityAndOtherProfile() throws Exception {
700         // enable the work tab feature flag
701         ResolverActivity.ENABLE_TABBED_VIEW = true;
702 
703         Intent sendIntent = createSendTextIntent();
704         List<ResolvedComponentInfo> resolvedComponentInfos =
705                 createResolvedComponentsForTestWithOtherProfile(3);
706         ResolveInfo toChoose = resolvedComponentInfos.get(1).getResolveInfoAt(0);
707 
708         when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent(
709                 Mockito.anyBoolean(),
710                 Mockito.anyBoolean(),
711                 Mockito.anyBoolean(),
712                 Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
713 
714         final IChooserWrapper activity = (IChooserWrapper)
715                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
716         waitForIdle();
717 
718         // The other entry is filtered to the last used slot
719         assertThat(activity.getAdapter().getCount(), is(2));
720 
721         ResolveInfo[] chosen = new ResolveInfo[1];
722         ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
723             chosen[0] = targetInfo.getResolveInfo();
724             return true;
725         };
726 
727         // Make a stable copy of the components as the original list may be modified
728         List<ResolvedComponentInfo> stableCopy =
729                 createResolvedComponentsForTestWithOtherProfile(3);
730         onView(withText(stableCopy.get(1).getResolveInfoAt(0).activityInfo.name))
731                 .perform(click());
732         waitForIdle();
733         assertThat(chosen[0], is(toChoose));
734     }
735 
736     @Test
copyTextToClipboard()737     public void copyTextToClipboard() throws Exception {
738         Intent sendIntent = createSendTextIntent();
739         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
740 
741         when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent(
742             Mockito.anyBoolean(),
743             Mockito.anyBoolean(),
744             Mockito.anyBoolean(),
745             Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
746 
747         final ChooserActivity activity =
748                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
749         waitForIdle();
750 
751         onView(withIdFromRuntimeResource("chooser_copy_button")).check(matches(isDisplayed()));
752         onView(withIdFromRuntimeResource("chooser_copy_button")).perform(click());
753         ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(
754                 Context.CLIPBOARD_SERVICE);
755         ClipData clipData = clipboard.getPrimaryClip();
756         assertThat("testing intent sending", is(clipData.getItemAt(0).getText()));
757 
758         ClipDescription clipDescription = clipData.getDescription();
759         assertThat("text/plain", is(clipDescription.getMimeType(0)));
760 
761         assertEquals(mActivityRule.getActivityResult().getResultCode(), RESULT_OK);
762     }
763 
764     @Test
copyTextToClipboardLogging()765     public void copyTextToClipboardLogging() throws Exception {
766         Intent sendIntent = createSendTextIntent();
767         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
768 
769         when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent(
770             Mockito.anyBoolean(),
771             Mockito.anyBoolean(),
772             Mockito.anyBoolean(),
773             Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
774 
775         MetricsLogger mockLogger = ChooserActivityOverrideData.getInstance().metricsLogger;
776         ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
777 
778         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
779         waitForIdle();
780 
781         onView(withIdFromRuntimeResource("chooser_copy_button")).check(matches(isDisplayed()));
782         onView(withIdFromRuntimeResource("chooser_copy_button")).perform(click());
783 
784         verify(mockLogger, atLeastOnce()).write(logMakerCaptor.capture());
785 
786         // The last captured event is the selection of the target.
787         assertThat(logMakerCaptor.getValue().getCategory(),
788                 is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SYSTEM_TARGET));
789         assertThat(logMakerCaptor.getValue().getSubtype(), is(1));
790     }
791 
792 
793     @Test
794     @Ignore
testNearbyShareLogging()795     public void testNearbyShareLogging() throws Exception {
796         Intent sendIntent = createSendTextIntent();
797         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
798 
799         when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent(
800                 Mockito.anyBoolean(),
801                 Mockito.anyBoolean(),
802                 Mockito.anyBoolean(),
803                 Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
804 
805         final IChooserWrapper activity = (IChooserWrapper)
806                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
807         waitForIdle();
808 
809         onView(withIdFromRuntimeResource("chooser_nearby_button")).check(matches(isDisplayed()));
810         onView(withIdFromRuntimeResource("chooser_nearby_button")).perform(click());
811 
812         ChooserActivityLoggerFake logger =
813                 (ChooserActivityLoggerFake) activity.getChooserActivityLogger();
814 
815         // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events.
816         logger.removeCallsForUiEventsOfType(
817                 ChooserActivityLogger.SharesheetStandardEvent
818                         .SHARESHEET_DIRECT_LOAD_COMPLETE.getId());
819 
820         // SHARESHEET_TRIGGERED:
821         assertThat(logger.event(0).getId(),
822                 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId()));
823 
824         // SHARESHEET_STARTED:
825         assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED));
826         assertThat(logger.get(1).intent, is(Intent.ACTION_SEND));
827         assertThat(logger.get(1).mimeType, is("text/plain"));
828         assertThat(logger.get(1).packageName, is(
829                 InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName()));
830         assertThat(logger.get(1).appProvidedApp, is(0));
831         assertThat(logger.get(1).appProvidedDirect, is(0));
832         assertThat(logger.get(1).isWorkprofile, is(false));
833         assertThat(logger.get(1).previewType, is(3));
834 
835         // SHARESHEET_APP_LOAD_COMPLETE:
836         assertThat(logger.event(2).getId(),
837                 is(ChooserActivityLogger
838                         .SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId()));
839 
840         // Next are just artifacts of test set-up:
841         assertThat(logger.event(3).getId(),
842                 is(ChooserActivityLogger
843                         .SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId()));
844         assertThat(logger.event(4).getId(),
845                 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_EXPANDED.getId()));
846 
847         // SHARESHEET_NEARBY_TARGET_SELECTED:
848         assertThat(logger.get(5).atomId, is(FrameworkStatsLog.RANKING_SELECTED));
849         assertThat(logger.get(5).targetType,
850                 is(ChooserActivityLogger
851                         .SharesheetTargetSelectedEvent.SHARESHEET_NEARBY_TARGET_SELECTED.getId()));
852 
853         // No more events.
854         assertThat(logger.numCalls(), is(6));
855     }
856 
857 
858 
859     @Test @Ignore
testEditImageLogs()860     public void testEditImageLogs() throws Exception {
861         Intent sendIntent = createSendImageIntent(
862                 Uri.parse("android.resource://com.android.frameworks.coretests/"
863                         + com.android.frameworks.coretests.R.drawable.test320x240));
864 
865         ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
866         ChooserActivityOverrideData.getInstance().isImageType = true;
867 
868         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
869 
870         when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent(
871                 Mockito.anyBoolean(),
872                 Mockito.anyBoolean(),
873                 Mockito.anyBoolean(),
874                 Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
875 
876         final IChooserWrapper activity = (IChooserWrapper)
877                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
878         waitForIdle();
879 
880         onView(withIdFromRuntimeResource("chooser_edit_button")).check(matches(isDisplayed()));
881         onView(withIdFromRuntimeResource("chooser_edit_button")).perform(click());
882 
883         ChooserActivityLoggerFake logger =
884                 (ChooserActivityLoggerFake) activity.getChooserActivityLogger();
885 
886         // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events.
887         logger.removeCallsForUiEventsOfType(
888                 ChooserActivityLogger.SharesheetStandardEvent
889                         .SHARESHEET_DIRECT_LOAD_COMPLETE.getId());
890 
891         // SHARESHEET_TRIGGERED:
892         assertThat(logger.event(0).getId(),
893                 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId()));
894 
895         // SHARESHEET_STARTED:
896         assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED));
897         assertThat(logger.get(1).intent, is(Intent.ACTION_SEND));
898         assertThat(logger.get(1).mimeType, is("image/png"));
899         assertThat(logger.get(1).packageName, is(
900                 InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName()));
901         assertThat(logger.get(1).appProvidedApp, is(0));
902         assertThat(logger.get(1).appProvidedDirect, is(0));
903         assertThat(logger.get(1).isWorkprofile, is(false));
904         assertThat(logger.get(1).previewType, is(1));
905 
906         // SHARESHEET_APP_LOAD_COMPLETE:
907         assertThat(logger.event(2).getId(),
908                 is(ChooserActivityLogger
909                         .SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId()));
910 
911         // Next are just artifacts of test set-up:
912         assertThat(logger.event(3).getId(),
913                 is(ChooserActivityLogger
914                         .SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId()));
915         assertThat(logger.event(4).getId(),
916                 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_EXPANDED.getId()));
917 
918         // SHARESHEET_EDIT_TARGET_SELECTED:
919         assertThat(logger.get(5).atomId, is(FrameworkStatsLog.RANKING_SELECTED));
920         assertThat(logger.get(5).targetType,
921                 is(ChooserActivityLogger
922                         .SharesheetTargetSelectedEvent.SHARESHEET_EDIT_TARGET_SELECTED.getId()));
923 
924         // No more events.
925         assertThat(logger.numCalls(), is(6));
926     }
927 
928 
929     @Test
oneVisibleImagePreview()930     public void oneVisibleImagePreview() throws InterruptedException {
931         Uri uri = Uri.parse("android.resource://com.android.frameworks.coretests/"
932                 + com.android.frameworks.coretests.R.drawable.test320x240);
933 
934         ArrayList<Uri> uris = new ArrayList<>();
935         uris.add(uri);
936 
937         Intent sendIntent = createSendUriIntentWithPreview(uris);
938         ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
939         ChooserActivityOverrideData.getInstance().isImageType = true;
940 
941         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
942 
943         when(
944                 ChooserActivityOverrideData
945                         .getInstance()
946                         .resolverListController
947                         .getResolversForIntent(
948                                 Mockito.anyBoolean(),
949                                 Mockito.anyBoolean(),
950                                 Mockito.anyBoolean(),
951                                 Mockito.isA(List.class)))
952                 .thenReturn(resolvedComponentInfos);
953         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
954         waitForIdle();
955         onView(withIdFromRuntimeResource("content_preview_image_1_large"))
956                 .check(matches(isDisplayed()));
957         onView(withIdFromRuntimeResource("content_preview_image_2_large"))
958                 .check(matches(not(isDisplayed())));
959         onView(withIdFromRuntimeResource("content_preview_image_2_small"))
960                 .check(matches(not(isDisplayed())));
961         onView(withIdFromRuntimeResource("content_preview_image_3_small"))
962                 .check(matches(not(isDisplayed())));
963     }
964 
965     @Test
twoVisibleImagePreview()966     public void twoVisibleImagePreview() throws InterruptedException {
967         Uri uri = Uri.parse("android.resource://com.android.frameworks.coretests/"
968                 + com.android.frameworks.coretests.R.drawable.test320x240);
969 
970         ArrayList<Uri> uris = new ArrayList<>();
971         uris.add(uri);
972         uris.add(uri);
973 
974         Intent sendIntent = createSendUriIntentWithPreview(uris);
975         ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
976         ChooserActivityOverrideData.getInstance().isImageType = true;
977 
978         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
979 
980         when(
981                 ChooserActivityOverrideData
982                         .getInstance()
983                         .resolverListController
984                         .getResolversForIntent(
985                                 Mockito.anyBoolean(),
986                                 Mockito.anyBoolean(),
987                                 Mockito.anyBoolean(),
988                                 Mockito.isA(List.class)))
989                 .thenReturn(resolvedComponentInfos);
990         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
991         waitForIdle();
992         onView(withIdFromRuntimeResource("content_preview_image_1_large"))
993                 .check(matches(isDisplayed()));
994         onView(withIdFromRuntimeResource("content_preview_image_2_large"))
995                 .check(matches(isDisplayed()));
996         onView(withIdFromRuntimeResource("content_preview_image_2_small"))
997                 .check(matches(not(isDisplayed())));
998         onView(withIdFromRuntimeResource("content_preview_image_3_small"))
999                 .check(matches(not(isDisplayed())));
1000     }
1001 
1002     @Test
threeOrMoreVisibleImagePreview()1003     public void threeOrMoreVisibleImagePreview() throws InterruptedException {
1004         Uri uri = Uri.parse("android.resource://com.android.frameworks.coretests/"
1005                 + com.android.frameworks.coretests.R.drawable.test320x240);
1006 
1007         ArrayList<Uri> uris = new ArrayList<>();
1008         uris.add(uri);
1009         uris.add(uri);
1010         uris.add(uri);
1011         uris.add(uri);
1012         uris.add(uri);
1013 
1014         Intent sendIntent = createSendUriIntentWithPreview(uris);
1015         ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
1016         ChooserActivityOverrideData.getInstance().isImageType = true;
1017 
1018         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1019 
1020         when(
1021                 ChooserActivityOverrideData
1022                         .getInstance()
1023                         .resolverListController
1024                         .getResolversForIntent(
1025                                 Mockito.anyBoolean(),
1026                                 Mockito.anyBoolean(),
1027                                 Mockito.anyBoolean(),
1028                                 Mockito.isA(List.class)))
1029                 .thenReturn(resolvedComponentInfos);
1030         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1031         waitForIdle();
1032         onView(withIdFromRuntimeResource("content_preview_image_1_large"))
1033                 .check(matches(isDisplayed()));
1034         onView(withIdFromRuntimeResource("content_preview_image_2_large"))
1035                 .check(matches(not(isDisplayed())));
1036         onView(withIdFromRuntimeResource("content_preview_image_2_small"))
1037                 .check(matches(isDisplayed()));
1038         onView(withIdFromRuntimeResource("content_preview_image_3_small"))
1039                 .check(matches(isDisplayed()));
1040     }
1041 
1042     @Test
testOnCreateLogging()1043     public void testOnCreateLogging() {
1044         Intent sendIntent = createSendTextIntent();
1045         sendIntent.setType(TEST_MIME_TYPE);
1046 
1047         MetricsLogger mockLogger = ChooserActivityOverrideData.getInstance().metricsLogger;
1048         ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
1049         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "logger test"));
1050         waitForIdle();
1051         verify(mockLogger, atLeastOnce()).write(logMakerCaptor.capture());
1052         assertThat(logMakerCaptor.getAllValues().get(0).getCategory(),
1053                 is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
1054         assertThat(logMakerCaptor
1055                 .getAllValues().get(0)
1056                 .getTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS),
1057                 is(notNullValue()));
1058         assertThat(logMakerCaptor
1059                 .getAllValues().get(0)
1060                 .getTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE),
1061                 is(TEST_MIME_TYPE));
1062         assertThat(logMakerCaptor
1063                         .getAllValues().get(0)
1064                         .getSubtype(),
1065                 is(MetricsEvent.PARENT_PROFILE));
1066     }
1067 
1068     @Test
testOnCreateLoggingFromWorkProfile()1069     public void testOnCreateLoggingFromWorkProfile() {
1070         Intent sendIntent = createSendTextIntent();
1071         sendIntent.setType(TEST_MIME_TYPE);
1072         ChooserActivityOverrideData.getInstance().alternateProfileSetting =
1073                 MetricsEvent.MANAGED_PROFILE;
1074         MetricsLogger mockLogger = ChooserActivityOverrideData.getInstance().metricsLogger;
1075         ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
1076         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "logger test"));
1077         waitForIdle();
1078         verify(mockLogger, atLeastOnce()).write(logMakerCaptor.capture());
1079         assertThat(logMakerCaptor.getAllValues().get(0).getCategory(),
1080                 is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
1081         assertThat(logMakerCaptor
1082                         .getAllValues().get(0)
1083                         .getTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS),
1084                 is(notNullValue()));
1085         assertThat(logMakerCaptor
1086                         .getAllValues().get(0)
1087                         .getTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE),
1088                 is(TEST_MIME_TYPE));
1089         assertThat(logMakerCaptor
1090                         .getAllValues().get(0)
1091                         .getSubtype(),
1092                 is(MetricsEvent.MANAGED_PROFILE));
1093     }
1094 
1095     @Test
testEmptyPreviewLogging()1096     public void testEmptyPreviewLogging() {
1097         Intent sendIntent = createSendTextIntentWithPreview(null, null);
1098 
1099         MetricsLogger mockLogger = ChooserActivityOverrideData.getInstance().metricsLogger;
1100         ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
1101         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "empty preview logger test"));
1102         waitForIdle();
1103 
1104         verify(mockLogger, Mockito.times(1)).write(logMakerCaptor.capture());
1105         // First invocation is from onCreate
1106         assertThat(logMakerCaptor.getAllValues().get(0).getCategory(),
1107                 is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
1108     }
1109 
1110     @Test
testTitlePreviewLogging()1111     public void testTitlePreviewLogging() {
1112         Intent sendIntent = createSendTextIntentWithPreview("TestTitle", null);
1113 
1114         MetricsLogger mockLogger = ChooserActivityOverrideData.getInstance().metricsLogger;
1115         ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
1116 
1117         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1118 
1119         when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent(
1120             Mockito.anyBoolean(),
1121             Mockito.anyBoolean(),
1122             Mockito.anyBoolean(),
1123             Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
1124 
1125         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1126         waitForIdle();
1127         // Second invocation is from onCreate
1128         verify(mockLogger, Mockito.times(2)).write(logMakerCaptor.capture());
1129         assertThat(logMakerCaptor.getAllValues().get(0).getSubtype(),
1130                 is(CONTENT_PREVIEW_TEXT));
1131         assertThat(logMakerCaptor.getAllValues().get(0).getCategory(),
1132                 is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
1133     }
1134 
1135     @Test
testImagePreviewLogging()1136     public void testImagePreviewLogging() {
1137         Uri uri = Uri.parse("android.resource://com.android.frameworks.coretests/"
1138                 + com.android.frameworks.coretests.R.drawable.test320x240);
1139 
1140         ArrayList<Uri> uris = new ArrayList<>();
1141         uris.add(uri);
1142 
1143         Intent sendIntent = createSendUriIntentWithPreview(uris);
1144         ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
1145         ChooserActivityOverrideData.getInstance().isImageType = true;
1146 
1147         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1148 
1149         when(
1150                 ChooserActivityOverrideData
1151                         .getInstance()
1152                         .resolverListController
1153                         .getResolversForIntent(
1154                                 Mockito.anyBoolean(),
1155                                 Mockito.anyBoolean(),
1156                                 Mockito.anyBoolean(),
1157                                 Mockito.isA(List.class)))
1158                 .thenReturn(resolvedComponentInfos);
1159 
1160         MetricsLogger mockLogger = ChooserActivityOverrideData.getInstance().metricsLogger;
1161         ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
1162         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1163         waitForIdle();
1164         verify(mockLogger, Mockito.times(2)).write(logMakerCaptor.capture());
1165         // First invocation is from onCreate
1166         assertThat(logMakerCaptor.getAllValues().get(0).getSubtype(),
1167                 is(CONTENT_PREVIEW_IMAGE));
1168         assertThat(logMakerCaptor.getAllValues().get(0).getCategory(),
1169                 is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
1170     }
1171 
1172     @Test
oneVisibleFilePreview()1173     public void oneVisibleFilePreview() throws InterruptedException {
1174         Uri uri = Uri.parse("content://com.android.frameworks.coretests/app.pdf");
1175 
1176         ArrayList<Uri> uris = new ArrayList<>();
1177         uris.add(uri);
1178 
1179         Intent sendIntent = createSendUriIntentWithPreview(uris);
1180 
1181         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1182 
1183         when(
1184                 ChooserActivityOverrideData
1185                     .getInstance()
1186                     .resolverListController
1187                     .getResolversForIntent(
1188                             Mockito.anyBoolean(),
1189                             Mockito.anyBoolean(),
1190                             Mockito.anyBoolean(),
1191                             Mockito.isA(List.class)))
1192                 .thenReturn(resolvedComponentInfos);
1193         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1194         waitForIdle();
1195         onView(withIdFromRuntimeResource("content_preview_filename")).check(matches(isDisplayed()));
1196         onView(withIdFromRuntimeResource("content_preview_filename"))
1197                 .check(matches(withText("app.pdf")));
1198         onView(withIdFromRuntimeResource("content_preview_file_icon"))
1199                 .check(matches(isDisplayed()));
1200     }
1201 
1202 
1203     @Test
moreThanOneVisibleFilePreview()1204     public void moreThanOneVisibleFilePreview() throws InterruptedException {
1205         Uri uri = Uri.parse("content://com.android.frameworks.coretests/app.pdf");
1206 
1207         ArrayList<Uri> uris = new ArrayList<>();
1208         uris.add(uri);
1209         uris.add(uri);
1210         uris.add(uri);
1211 
1212         Intent sendIntent = createSendUriIntentWithPreview(uris);
1213 
1214         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1215 
1216         when(
1217                 ChooserActivityOverrideData
1218                         .getInstance()
1219                         .resolverListController
1220                         .getResolversForIntent(
1221                                 Mockito.anyBoolean(),
1222                                 Mockito.anyBoolean(),
1223                                 Mockito.anyBoolean(),
1224                                 Mockito.isA(List.class)))
1225                 .thenReturn(resolvedComponentInfos);
1226         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1227         waitForIdle();
1228         onView(withIdFromRuntimeResource("content_preview_filename"))
1229                 .check(matches(isDisplayed()));
1230         onView(withIdFromRuntimeResource("content_preview_filename"))
1231                 .check(matches(withText("app.pdf + 2 files")));
1232         onView(withIdFromRuntimeResource("content_preview_file_icon"))
1233                 .check(matches(isDisplayed()));
1234     }
1235 
1236     @Test
contentProviderThrowSecurityException()1237     public void contentProviderThrowSecurityException() throws InterruptedException {
1238         Uri uri = Uri.parse("content://com.android.frameworks.coretests/app.pdf");
1239 
1240         ArrayList<Uri> uris = new ArrayList<>();
1241         uris.add(uri);
1242 
1243         Intent sendIntent = createSendUriIntentWithPreview(uris);
1244 
1245         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1246         when(
1247                 ChooserActivityOverrideData
1248                         .getInstance()
1249                         .resolverListController
1250                         .getResolversForIntent(
1251                                 Mockito.anyBoolean(),
1252                                 Mockito.anyBoolean(),
1253                                 Mockito.anyBoolean(),
1254                                 Mockito.isA(List.class)))
1255                 .thenReturn(resolvedComponentInfos);
1256 
1257         ChooserActivityOverrideData.getInstance().resolverForceException = true;
1258 
1259         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1260         waitForIdle();
1261         onView(withIdFromRuntimeResource("content_preview_filename")).check(matches(isDisplayed()));
1262         onView(withIdFromRuntimeResource("content_preview_filename"))
1263                 .check(matches(withText("app.pdf")));
1264         onView(withIdFromRuntimeResource("content_preview_file_icon"))
1265                 .check(matches(isDisplayed()));
1266     }
1267 
1268     @Test
contentProviderReturnsNoColumns()1269     public void contentProviderReturnsNoColumns() throws InterruptedException {
1270         Uri uri = Uri.parse("content://com.android.frameworks.coretests/app.pdf");
1271 
1272         ArrayList<Uri> uris = new ArrayList<>();
1273         uris.add(uri);
1274         uris.add(uri);
1275 
1276         Intent sendIntent = createSendUriIntentWithPreview(uris);
1277 
1278         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1279         when(
1280                 ChooserActivityOverrideData
1281                         .getInstance()
1282                         .resolverListController
1283                         .getResolversForIntent(
1284                                 Mockito.anyBoolean(),
1285                                 Mockito.anyBoolean(),
1286                                 Mockito.anyBoolean(),
1287                                 Mockito.isA(List.class)))
1288                 .thenReturn(resolvedComponentInfos);
1289 
1290         Cursor cursor = mock(Cursor.class);
1291         when(cursor.getCount()).thenReturn(1);
1292         Mockito.doNothing().when(cursor).close();
1293         when(cursor.moveToFirst()).thenReturn(true);
1294         when(cursor.getColumnIndex(Mockito.anyString())).thenReturn(-1);
1295 
1296         ChooserActivityOverrideData.getInstance().resolverCursor = cursor;
1297 
1298         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1299         waitForIdle();
1300         onView(withIdFromRuntimeResource("content_preview_filename")).check(matches(isDisplayed()));
1301         onView(withIdFromRuntimeResource("content_preview_filename"))
1302                 .check(matches(withText("app.pdf + 1 file")));
1303         onView(withIdFromRuntimeResource("content_preview_file_icon"))
1304                 .check(matches(isDisplayed()));
1305     }
1306 
1307     @Test
testGetBaseScore()1308     public void testGetBaseScore() {
1309         final float testBaseScore = 0.89f;
1310 
1311         Intent sendIntent = createSendTextIntent();
1312         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1313 
1314         when(
1315                 ChooserActivityOverrideData
1316                         .getInstance()
1317                         .resolverListController
1318                         .getResolversForIntent(
1319                                 Mockito.anyBoolean(),
1320                                 Mockito.anyBoolean(),
1321                                 Mockito.anyBoolean(),
1322                                 Mockito.isA(List.class)))
1323                 .thenReturn(resolvedComponentInfos);
1324         when(
1325                 ChooserActivityOverrideData
1326                         .getInstance()
1327                         .resolverListController
1328                         .getScore(Mockito.isA(DisplayResolveInfo.class)))
1329                 .thenReturn(testBaseScore);
1330 
1331         final IChooserWrapper activity = (IChooserWrapper)
1332                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1333         waitForIdle();
1334 
1335         final DisplayResolveInfo testDri =
1336                 activity.createTestDisplayResolveInfo(sendIntent,
1337                 ResolverDataProvider.createResolveInfo(
1338                         3, 0, PERSONAL_USER_HANDLE),
1339                         "testLabel",
1340                         "testInfo",
1341                         sendIntent,
1342                 /* resolveInfoPresentationGetter */ null);
1343         final ChooserListAdapter adapter = activity.getAdapter();
1344 
1345         assertThat(adapter.getBaseScore(null, 0), is(CALLER_TARGET_SCORE_BOOST));
1346         assertThat(adapter.getBaseScore(testDri, TARGET_TYPE_DEFAULT), is(testBaseScore));
1347         assertThat(adapter.getBaseScore(testDri, TARGET_TYPE_CHOOSER_TARGET), is(testBaseScore));
1348         assertThat(adapter.getBaseScore(testDri, TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE),
1349                 is(testBaseScore * SHORTCUT_TARGET_SCORE_BOOST));
1350         assertThat(adapter.getBaseScore(testDri, TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER),
1351                 is(testBaseScore * SHORTCUT_TARGET_SCORE_BOOST));
1352     }
1353 
1354     @Test
testConvertToChooserTarget_predictionService()1355     public void testConvertToChooserTarget_predictionService() {
1356         Intent sendIntent = createSendTextIntent();
1357         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1358         when(
1359                 ChooserActivityOverrideData
1360                         .getInstance()
1361                         .resolverListController
1362                         .getResolversForIntent(
1363                                 Mockito.anyBoolean(),
1364                                 Mockito.anyBoolean(),
1365                                 Mockito.anyBoolean(),
1366                                 Mockito.isA(List.class)))
1367                 .thenReturn(resolvedComponentInfos);
1368 
1369         final ChooserActivity activity =
1370                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1371         waitForIdle();
1372 
1373         List<ShareShortcutInfo> shortcuts = createShortcuts(activity);
1374 
1375         int[] expectedOrderAllShortcuts = {0, 1, 2, 3};
1376         float[] expectedScoreAllShortcuts = {1.0f, 0.99f, 0.98f, 0.97f};
1377 
1378         List<ChooserTarget> chooserTargets = activity.convertToChooserTarget(shortcuts, shortcuts,
1379                 null, TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE);
1380         assertCorrectShortcutToChooserTargetConversion(shortcuts, chooserTargets,
1381                 expectedOrderAllShortcuts, expectedScoreAllShortcuts);
1382 
1383         List<ShareShortcutInfo> subset = new ArrayList<>();
1384         subset.add(shortcuts.get(1));
1385         subset.add(shortcuts.get(2));
1386         subset.add(shortcuts.get(3));
1387 
1388         int[] expectedOrderSubset = {1, 2, 3};
1389         float[] expectedScoreSubset = {0.99f, 0.98f, 0.97f};
1390 
1391         chooserTargets = activity.convertToChooserTarget(subset, shortcuts, null,
1392                 TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE);
1393         assertCorrectShortcutToChooserTargetConversion(shortcuts, chooserTargets,
1394                 expectedOrderSubset, expectedScoreSubset);
1395     }
1396 
1397     @Test
testConvertToChooserTarget_shortcutManager()1398     public void testConvertToChooserTarget_shortcutManager() {
1399         Intent sendIntent = createSendTextIntent();
1400         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1401         when(
1402                 ChooserActivityOverrideData
1403                         .getInstance()
1404                         .resolverListController
1405                         .getResolversForIntent(
1406                                 Mockito.anyBoolean(),
1407                                 Mockito.anyBoolean(),
1408                                 Mockito.anyBoolean(),
1409                                 Mockito.isA(List.class)))
1410                 .thenReturn(resolvedComponentInfos);
1411 
1412         final ChooserActivity activity =
1413                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1414         waitForIdle();
1415 
1416         List<ShareShortcutInfo> shortcuts = createShortcuts(activity);
1417 
1418         int[] expectedOrderAllShortcuts = {2, 0, 3, 1};
1419         float[] expectedScoreAllShortcuts = {1.0f, 0.99f, 0.99f, 0.98f};
1420 
1421         List<ChooserTarget> chooserTargets = activity.convertToChooserTarget(shortcuts, shortcuts,
1422                 null, TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER);
1423         assertCorrectShortcutToChooserTargetConversion(shortcuts, chooserTargets,
1424                 expectedOrderAllShortcuts, expectedScoreAllShortcuts);
1425 
1426         List<ShareShortcutInfo> subset = new ArrayList<>();
1427         subset.add(shortcuts.get(1));
1428         subset.add(shortcuts.get(2));
1429         subset.add(shortcuts.get(3));
1430 
1431         int[] expectedOrderSubset = {2, 3, 1};
1432         float[] expectedScoreSubset = {1.0f, 0.99f, 0.98f};
1433 
1434         chooserTargets = activity.convertToChooserTarget(subset, shortcuts, null,
1435                 TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER);
1436         assertCorrectShortcutToChooserTargetConversion(shortcuts, chooserTargets,
1437                 expectedOrderSubset, expectedScoreSubset);
1438     }
1439 
1440     // This test is too long and too slow and should not be taken as an example for future tests.
1441     @Test @Ignore
testDirectTargetSelectionLogging()1442     public void testDirectTargetSelectionLogging() throws InterruptedException {
1443         Intent sendIntent = createSendTextIntent();
1444         // We need app targets for direct targets to get displayed
1445         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1446         when(
1447                 ChooserActivityOverrideData
1448                         .getInstance()
1449                         .resolverListController
1450                         .getResolversForIntent(
1451                                 Mockito.anyBoolean(),
1452                                 Mockito.anyBoolean(),
1453                                 Mockito.anyBoolean(),
1454                                 Mockito.isA(List.class)))
1455                 .thenReturn(resolvedComponentInfos);
1456 
1457         // Set up resources
1458         MetricsLogger mockLogger = ChooserActivityOverrideData.getInstance().metricsLogger;
1459         ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
1460         // Create direct share target
1461         List<ChooserTarget> serviceTargets = createDirectShareTargets(1, "");
1462         ResolveInfo ri = ResolverDataProvider.createResolveInfo(3, 0,
1463                 PERSONAL_USER_HANDLE);
1464 
1465         // Start activity
1466         final IChooserWrapper activity = (IChooserWrapper)
1467                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1468 
1469         // Insert the direct share target
1470         Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos = new HashMap<>();
1471         directShareToShortcutInfos.put(serviceTargets.get(0), null);
1472         InstrumentationRegistry.getInstrumentation().runOnMainSync(
1473                 () -> activity.getAdapter().addServiceResults(
1474                         activity.createTestDisplayResolveInfo(sendIntent,
1475                                 ri,
1476                                 "testLabel",
1477                                 "testInfo",
1478                                 sendIntent,
1479                                 /* resolveInfoPresentationGetter */ null),
1480                         serviceTargets,
1481                         TARGET_TYPE_CHOOSER_TARGET,
1482                         directShareToShortcutInfos)
1483         );
1484 
1485         // Thread.sleep shouldn't be a thing in an integration test but it's
1486         // necessary here because of the way the code is structured
1487         // TODO: restructure the tests b/129870719
1488         Thread.sleep(((ChooserActivity) activity).mListViewUpdateDelayMs);
1489 
1490         assertThat("Chooser should have 3 targets (2 apps, 1 direct)",
1491                 activity.getAdapter().getCount(), is(3));
1492         assertThat("Chooser should have exactly one selectable direct target",
1493                 activity.getAdapter().getSelectableServiceTargetCount(), is(1));
1494         assertThat("The resolver info must match the resolver info used to create the target",
1495                 activity.getAdapter().getItem(0).getResolveInfo(), is(ri));
1496 
1497         // Click on the direct target
1498         String name = serviceTargets.get(0).getTitle().toString();
1499         onView(withText(name))
1500                 .perform(click());
1501         waitForIdle();
1502 
1503         // Currently we're seeing 3 invocations
1504         //      1. ChooserActivity.onCreate()
1505         //      2. ChooserActivity$ChooserRowAdapter.createContentPreviewView()
1506         //      3. ChooserActivity.startSelected -- which is the one we're after
1507         verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
1508         assertThat(logMakerCaptor.getAllValues().get(2).getCategory(),
1509                 is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET));
1510         String hashedName = (String) logMakerCaptor
1511                 .getAllValues().get(2).getTaggedData(MetricsEvent.FIELD_HASHED_TARGET_NAME);
1512         assertThat("Hash is not predictable but must be obfuscated",
1513                 hashedName, is(not(name)));
1514         assertThat("The packages shouldn't match for app target and direct target", logMakerCaptor
1515                 .getAllValues().get(2).getTaggedData(MetricsEvent.FIELD_RANKED_POSITION), is(-1));
1516     }
1517 
1518     // This test is too long and too slow and should not be taken as an example for future tests.
1519     @Test @Ignore
testDirectTargetLoggingWithRankedAppTarget()1520     public void testDirectTargetLoggingWithRankedAppTarget() throws InterruptedException {
1521         Intent sendIntent = createSendTextIntent();
1522         // We need app targets for direct targets to get displayed
1523         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1524         when(
1525                 ChooserActivityOverrideData
1526                         .getInstance()
1527                         .resolverListController
1528                         .getResolversForIntent(
1529                                 Mockito.anyBoolean(),
1530                                 Mockito.anyBoolean(),
1531                                 Mockito.anyBoolean(),
1532                                 Mockito.isA(List.class)))
1533                 .thenReturn(resolvedComponentInfos);
1534 
1535         // Set up resources
1536         MetricsLogger mockLogger = ChooserActivityOverrideData.getInstance().metricsLogger;
1537         ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
1538         // Create direct share target
1539         List<ChooserTarget> serviceTargets = createDirectShareTargets(1,
1540                 resolvedComponentInfos.get(0).getResolveInfoAt(0).activityInfo.packageName);
1541         ResolveInfo ri = ResolverDataProvider.createResolveInfo(3, 0,
1542                 PERSONAL_USER_HANDLE);
1543 
1544         // Start activity
1545         final IChooserWrapper activity = (IChooserWrapper)
1546                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1547 
1548         // Insert the direct share target
1549         Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos = new HashMap<>();
1550         directShareToShortcutInfos.put(serviceTargets.get(0), null);
1551         InstrumentationRegistry.getInstrumentation().runOnMainSync(
1552                 () -> activity.getAdapter().addServiceResults(
1553                         activity.createTestDisplayResolveInfo(sendIntent,
1554                                 ri,
1555                                 "testLabel",
1556                                 "testInfo",
1557                                 sendIntent,
1558                                 /* resolveInfoPresentationGetter */ null),
1559                         serviceTargets,
1560                         TARGET_TYPE_CHOOSER_TARGET,
1561                         directShareToShortcutInfos)
1562         );
1563         // Thread.sleep shouldn't be a thing in an integration test but it's
1564         // necessary here because of the way the code is structured
1565         // TODO: restructure the tests b/129870719
1566         Thread.sleep(((ChooserActivity) activity).mListViewUpdateDelayMs);
1567 
1568         assertThat("Chooser should have 3 targets (2 apps, 1 direct)",
1569                 activity.getAdapter().getCount(), is(3));
1570         assertThat("Chooser should have exactly one selectable direct target",
1571                 activity.getAdapter().getSelectableServiceTargetCount(), is(1));
1572         assertThat("The resolver info must match the resolver info used to create the target",
1573                 activity.getAdapter().getItem(0).getResolveInfo(), is(ri));
1574 
1575         // Click on the direct target
1576         String name = serviceTargets.get(0).getTitle().toString();
1577         onView(withText(name))
1578                 .perform(click());
1579         waitForIdle();
1580 
1581         // Currently we're seeing 3 invocations
1582         //      1. ChooserActivity.onCreate()
1583         //      2. ChooserActivity$ChooserRowAdapter.createContentPreviewView()
1584         //      3. ChooserActivity.startSelected -- which is the one we're after
1585         verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
1586         assertThat(logMakerCaptor.getAllValues().get(2).getCategory(),
1587                 is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET));
1588         assertThat("The packages should match for app target and direct target", logMakerCaptor
1589                 .getAllValues().get(2).getTaggedData(MetricsEvent.FIELD_RANKED_POSITION), is(0));
1590     }
1591 
1592     @Test @Ignore
testShortcutTargetWithApplyAppLimits()1593     public void testShortcutTargetWithApplyAppLimits() throws InterruptedException {
1594         // Set up resources
1595         ChooserActivityOverrideData.getInstance().resources = Mockito.spy(
1596                 InstrumentationRegistry.getInstrumentation().getContext().getResources());
1597         when(
1598                 ChooserActivityOverrideData
1599                         .getInstance()
1600                         .resources
1601                         .getInteger(
1602                               getRuntimeResourceId("config_maxShortcutTargetsPerApp", "integer")))
1603                 .thenReturn(1);
1604         Intent sendIntent = createSendTextIntent();
1605         // We need app targets for direct targets to get displayed
1606         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1607         when(
1608                 ChooserActivityOverrideData
1609                         .getInstance()
1610                         .resolverListController
1611                         .getResolversForIntent(
1612                                 Mockito.anyBoolean(),
1613                                 Mockito.anyBoolean(),
1614                                 Mockito.anyBoolean(),
1615                                 Mockito.isA(List.class)))
1616                 .thenReturn(resolvedComponentInfos);
1617         // Create direct share target
1618         List<ChooserTarget> serviceTargets = createDirectShareTargets(2,
1619                 resolvedComponentInfos.get(0).getResolveInfoAt(0).activityInfo.packageName);
1620         ResolveInfo ri = ResolverDataProvider.createResolveInfo(3, 0,
1621                 PERSONAL_USER_HANDLE);
1622 
1623         // Start activity
1624         final ChooserActivity activity =
1625                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1626         final IChooserWrapper wrapper = (IChooserWrapper) activity;
1627 
1628         // Insert the direct share target
1629         Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos = new HashMap<>();
1630         List<ShareShortcutInfo> shortcutInfos = createShortcuts(activity);
1631         directShareToShortcutInfos.put(serviceTargets.get(0),
1632                 shortcutInfos.get(0).getShortcutInfo());
1633         directShareToShortcutInfos.put(serviceTargets.get(1),
1634                 shortcutInfos.get(1).getShortcutInfo());
1635         InstrumentationRegistry.getInstrumentation().runOnMainSync(
1636                 () -> wrapper.getAdapter().addServiceResults(
1637                         wrapper.createTestDisplayResolveInfo(sendIntent,
1638                                 ri,
1639                                 "testLabel",
1640                                 "testInfo",
1641                                 sendIntent,
1642                                 /* resolveInfoPresentationGetter */ null),
1643                         serviceTargets,
1644                         TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE,
1645                         directShareToShortcutInfos)
1646         );
1647         // Thread.sleep shouldn't be a thing in an integration test but it's
1648         // necessary here because of the way the code is structured
1649         // TODO: restructure the tests b/129870719
1650         Thread.sleep(((ChooserActivity) activity).mListViewUpdateDelayMs);
1651 
1652         assertThat("Chooser should have 3 targets (2 apps, 1 direct)",
1653                 wrapper.getAdapter().getCount(), is(3));
1654         assertThat("Chooser should have exactly one selectable direct target",
1655                 wrapper.getAdapter().getSelectableServiceTargetCount(), is(1));
1656         assertThat("The resolver info must match the resolver info used to create the target",
1657                 wrapper.getAdapter().getItem(0).getResolveInfo(), is(ri));
1658         assertThat("The display label must match",
1659                 wrapper.getAdapter().getItem(0).getDisplayLabel(), is("testTitle0"));
1660     }
1661 
1662     @Test @Ignore
testShortcutTargetWithoutApplyAppLimits()1663     public void testShortcutTargetWithoutApplyAppLimits() throws InterruptedException {
1664         DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
1665                 SystemUiDeviceConfigFlags.APPLY_SHARING_APP_LIMITS_IN_SYSUI,
1666                 Boolean.toString(false),
1667                 true /* makeDefault*/);
1668         // Set up resources
1669         ChooserActivityOverrideData.getInstance().resources = Mockito.spy(
1670                 InstrumentationRegistry.getInstrumentation().getContext().getResources());
1671         when(
1672                 ChooserActivityOverrideData
1673                         .getInstance()
1674                         .resources
1675                         .getInteger(
1676                               getRuntimeResourceId("config_maxShortcutTargetsPerApp", "integer")))
1677                 .thenReturn(1);
1678         Intent sendIntent = createSendTextIntent();
1679         // We need app targets for direct targets to get displayed
1680         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
1681         when(
1682                 ChooserActivityOverrideData
1683                         .getInstance()
1684                         .resolverListController
1685                         .getResolversForIntent(
1686                                 Mockito.anyBoolean(),
1687                                 Mockito.anyBoolean(),
1688                                 Mockito.anyBoolean(),
1689                                 Mockito.isA(List.class)))
1690                 .thenReturn(resolvedComponentInfos);
1691         // Create direct share target
1692         List<ChooserTarget> serviceTargets = createDirectShareTargets(2,
1693                 resolvedComponentInfos.get(0).getResolveInfoAt(0).activityInfo.packageName);
1694         ResolveInfo ri = ResolverDataProvider.createResolveInfo(3, 0,
1695                 PERSONAL_USER_HANDLE);
1696 
1697         // Start activity
1698         final ChooserActivity activity =
1699                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1700         final IChooserWrapper wrapper = (IChooserWrapper) activity;
1701 
1702         // Insert the direct share target
1703         Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos = new HashMap<>();
1704         List<ShareShortcutInfo> shortcutInfos = createShortcuts(activity);
1705         directShareToShortcutInfos.put(serviceTargets.get(0),
1706                 shortcutInfos.get(0).getShortcutInfo());
1707         directShareToShortcutInfos.put(serviceTargets.get(1),
1708                 shortcutInfos.get(1).getShortcutInfo());
1709         InstrumentationRegistry.getInstrumentation().runOnMainSync(
1710                 () -> wrapper.getAdapter().addServiceResults(
1711                         wrapper.createTestDisplayResolveInfo(sendIntent,
1712                                 ri,
1713                                 "testLabel",
1714                                 "testInfo",
1715                                 sendIntent,
1716                                 /* resolveInfoPresentationGetter */ null),
1717                         serviceTargets,
1718                         TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE,
1719                         directShareToShortcutInfos)
1720         );
1721         // Thread.sleep shouldn't be a thing in an integration test but it's
1722         // necessary here because of the way the code is structured
1723         // TODO: restructure the tests b/129870719
1724         Thread.sleep(((ChooserActivity) activity).mListViewUpdateDelayMs);
1725 
1726         assertThat("Chooser should have 4 targets (2 apps, 2 direct)",
1727                 wrapper.getAdapter().getCount(), is(4));
1728         assertThat("Chooser should have exactly two selectable direct target",
1729                 wrapper.getAdapter().getSelectableServiceTargetCount(), is(2));
1730         assertThat("The resolver info must match the resolver info used to create the target",
1731                 wrapper.getAdapter().getItem(0).getResolveInfo(), is(ri));
1732         assertThat("The display label must match",
1733                 wrapper.getAdapter().getItem(0).getDisplayLabel(), is("testTitle0"));
1734         assertThat("The display label must match",
1735                 wrapper.getAdapter().getItem(1).getDisplayLabel(), is("testTitle1"));
1736     }
1737 
1738     @Test
testUpdateMaxTargetsPerRow_columnCountIsUpdated()1739     public void testUpdateMaxTargetsPerRow_columnCountIsUpdated() throws InterruptedException {
1740         updateMaxTargetsPerRowResource(/* targetsPerRow= */ 4);
1741         givenAppTargets(/* appCount= */ 16);
1742         Intent sendIntent = createSendTextIntent();
1743         final ChooserActivity activity =
1744                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1745 
1746         updateMaxTargetsPerRowResource(/* targetsPerRow= */ 6);
1747         InstrumentationRegistry.getInstrumentation()
1748                 .runOnMainSync(() -> activity.onConfigurationChanged(
1749                         InstrumentationRegistry.getInstrumentation()
1750                                 .getContext().getResources().getConfiguration()));
1751 
1752         waitForIdle();
1753         onView(withIdFromRuntimeResource("resolver_list"))
1754                 .check(matches(withGridColumnCount(6)));
1755     }
1756 
1757     // This test is too long and too slow and should not be taken as an example for future tests.
1758     @Test @Ignore
testDirectTargetLoggingWithAppTargetNotRankedPortrait()1759     public void testDirectTargetLoggingWithAppTargetNotRankedPortrait()
1760             throws InterruptedException {
1761         testDirectTargetLoggingWithAppTargetNotRanked(Configuration.ORIENTATION_PORTRAIT, 4);
1762     }
1763 
1764     @Test @Ignore
testDirectTargetLoggingWithAppTargetNotRankedLandscape()1765     public void testDirectTargetLoggingWithAppTargetNotRankedLandscape()
1766             throws InterruptedException {
1767         testDirectTargetLoggingWithAppTargetNotRanked(Configuration.ORIENTATION_LANDSCAPE, 8);
1768     }
1769 
testDirectTargetLoggingWithAppTargetNotRanked( int orientation, int appTargetsExpected )1770     private void testDirectTargetLoggingWithAppTargetNotRanked(
1771             int orientation, int appTargetsExpected
1772     ) throws InterruptedException {
1773         Configuration configuration =
1774                 new Configuration(InstrumentationRegistry.getInstrumentation().getContext()
1775                         .getResources().getConfiguration());
1776         configuration.orientation = orientation;
1777 
1778         ChooserActivityOverrideData.getInstance().resources = Mockito.spy(
1779                 InstrumentationRegistry.getInstrumentation().getContext().getResources());
1780         when(
1781                 ChooserActivityOverrideData
1782                         .getInstance()
1783                         .resources
1784                         .getConfiguration())
1785                 .thenReturn(configuration);
1786 
1787         Intent sendIntent = createSendTextIntent();
1788         // We need app targets for direct targets to get displayed
1789         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(15);
1790         when(
1791                 ChooserActivityOverrideData
1792                         .getInstance()
1793                         .resolverListController
1794                         .getResolversForIntent(
1795                                 Mockito.anyBoolean(),
1796                                 Mockito.anyBoolean(),
1797                                 Mockito.anyBoolean(),
1798                                 Mockito.isA(List.class)))
1799                 .thenReturn(resolvedComponentInfos);
1800 
1801         // Set up resources
1802         MetricsLogger mockLogger = ChooserActivityOverrideData.getInstance().metricsLogger;
1803         ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
1804         // Create direct share target
1805         List<ChooserTarget> serviceTargets = createDirectShareTargets(1,
1806                 resolvedComponentInfos.get(14).getResolveInfoAt(0).activityInfo.packageName);
1807         ResolveInfo ri = ResolverDataProvider.createResolveInfo(16, 0,
1808                 PERSONAL_USER_HANDLE);
1809 
1810         // Start activity
1811         final IChooserWrapper activity = (IChooserWrapper)
1812                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
1813         final IChooserWrapper wrapper = (IChooserWrapper) activity;
1814         // Insert the direct share target
1815         Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos = new HashMap<>();
1816         directShareToShortcutInfos.put(serviceTargets.get(0), null);
1817         InstrumentationRegistry.getInstrumentation().runOnMainSync(
1818                 () -> wrapper.getAdapter().addServiceResults(
1819                         wrapper.createTestDisplayResolveInfo(sendIntent,
1820                                 ri,
1821                                 "testLabel",
1822                                 "testInfo",
1823                                 sendIntent,
1824                                 /* resolveInfoPresentationGetter */ null),
1825                         serviceTargets,
1826                         TARGET_TYPE_CHOOSER_TARGET,
1827                         directShareToShortcutInfos)
1828         );
1829         // Thread.sleep shouldn't be a thing in an integration test but it's
1830         // necessary here because of the way the code is structured
1831         // TODO: restructure the tests b/129870719
1832         Thread.sleep(((ChooserActivity) activity).mListViewUpdateDelayMs);
1833 
1834         assertThat(
1835                 String.format("Chooser should have %d targets (%d apps, 1 direct, 15 A-Z)",
1836                         appTargetsExpected + 16, appTargetsExpected),
1837                 wrapper.getAdapter().getCount(), is(appTargetsExpected + 16));
1838         assertThat("Chooser should have exactly one selectable direct target",
1839                 wrapper.getAdapter().getSelectableServiceTargetCount(), is(1));
1840         assertThat("The resolver info must match the resolver info used to create the target",
1841                 wrapper.getAdapter().getItem(0).getResolveInfo(), is(ri));
1842 
1843         // Click on the direct target
1844         String name = serviceTargets.get(0).getTitle().toString();
1845         onView(withText(name))
1846                 .perform(click());
1847         waitForIdle();
1848 
1849         // Currently we're seeing 3 invocations
1850         //      1. ChooserActivity.onCreate()
1851         //      2. ChooserActivity$ChooserRowAdapter.createContentPreviewView()
1852         //      3. ChooserActivity.startSelected -- which is the one we're after
1853         verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
1854         assertThat(logMakerCaptor.getAllValues().get(2).getCategory(),
1855                 is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET));
1856         assertThat("The packages shouldn't match for app target and direct target", logMakerCaptor
1857                 .getAllValues().get(2).getTaggedData(MetricsEvent.FIELD_RANKED_POSITION), is(-1));
1858     }
1859 
1860     @Test
testWorkTab_displayedWhenWorkProfileUserAvailable()1861     public void testWorkTab_displayedWhenWorkProfileUserAvailable() {
1862         // enable the work tab feature flag
1863         ResolverActivity.ENABLE_TABBED_VIEW = true;
1864         Intent sendIntent = createSendTextIntent();
1865         sendIntent.setType(TEST_MIME_TYPE);
1866         markWorkProfileUserAvailable();
1867 
1868         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
1869         waitForIdle();
1870 
1871         onView(withIdFromRuntimeResource("tabs")).check(matches(isDisplayed()));
1872     }
1873 
1874     @Test
testWorkTab_hiddenWhenWorkProfileUserNotAvailable()1875     public void testWorkTab_hiddenWhenWorkProfileUserNotAvailable() {
1876         // enable the work tab feature flag
1877         ResolverActivity.ENABLE_TABBED_VIEW = true;
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(withIdFromRuntimeResource("tabs")).check(matches(not(isDisplayed())));
1885     }
1886 
1887     @Test
testWorkTab_eachTabUsesExpectedAdapter()1888     public void testWorkTab_eachTabUsesExpectedAdapter() {
1889         // enable the work tab feature flag
1890         ResolverActivity.ENABLE_TABBED_VIEW = true;
1891         int personalProfileTargets = 3;
1892         int otherProfileTargets = 1;
1893         List<ResolvedComponentInfo> personalResolvedComponentInfos =
1894                 createResolvedComponentsForTestWithOtherProfile(
1895                         personalProfileTargets + otherProfileTargets, /* userID */ 10);
1896         int workProfileTargets = 4;
1897         List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(
1898                 workProfileTargets);
1899         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
1900         Intent sendIntent = createSendTextIntent();
1901         sendIntent.setType(TEST_MIME_TYPE);
1902         markWorkProfileUserAvailable();
1903 
1904         final IChooserWrapper activity = (IChooserWrapper)
1905                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
1906         waitForIdle();
1907 
1908         assertThat(activity.getCurrentUserHandle().getIdentifier(), is(0));
1909         onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
1910         assertThat(activity.getCurrentUserHandle().getIdentifier(), is(10));
1911         assertThat(activity.getPersonalListAdapter().getCount(), is(personalProfileTargets));
1912         assertThat(activity.getWorkListAdapter().getCount(), is(workProfileTargets));
1913     }
1914 
1915     @Test
testWorkTab_workProfileHasExpectedNumberOfTargets()1916     public void testWorkTab_workProfileHasExpectedNumberOfTargets() throws InterruptedException {
1917         // enable the work tab feature flag
1918         ResolverActivity.ENABLE_TABBED_VIEW = true;
1919         markWorkProfileUserAvailable();
1920         int workProfileTargets = 4;
1921         List<ResolvedComponentInfo> personalResolvedComponentInfos =
1922                 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
1923         List<ResolvedComponentInfo> workResolvedComponentInfos =
1924                 createResolvedComponentsForTest(workProfileTargets);
1925         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
1926         Intent sendIntent = createSendTextIntent();
1927         sendIntent.setType(TEST_MIME_TYPE);
1928 
1929         final IChooserWrapper activity = (IChooserWrapper)
1930                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
1931         waitForIdle();
1932         onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
1933         waitForIdle();
1934 
1935         assertThat(activity.getWorkListAdapter().getCount(), is(workProfileTargets));
1936     }
1937 
1938     @Test @Ignore
testWorkTab_selectingWorkTabAppOpensAppInWorkProfile()1939     public void testWorkTab_selectingWorkTabAppOpensAppInWorkProfile() throws InterruptedException {
1940         // enable the work tab feature flag
1941         ResolverActivity.ENABLE_TABBED_VIEW = true;
1942         markWorkProfileUserAvailable();
1943         List<ResolvedComponentInfo> personalResolvedComponentInfos =
1944                 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
1945         int workProfileTargets = 4;
1946         List<ResolvedComponentInfo> workResolvedComponentInfos =
1947                 createResolvedComponentsForTest(workProfileTargets);
1948         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
1949         Intent sendIntent = createSendTextIntent();
1950         sendIntent.setType(TEST_MIME_TYPE);
1951         ResolveInfo[] chosen = new ResolveInfo[1];
1952         ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
1953             chosen[0] = targetInfo.getResolveInfo();
1954             return true;
1955         };
1956 
1957         final IChooserWrapper activity = (IChooserWrapper)
1958                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
1959         waitForIdle();
1960         onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
1961         waitForIdle();
1962         // wait for the share sheet to expand
1963         Thread.sleep(((ChooserActivity) activity).mListViewUpdateDelayMs);
1964 
1965         onView(first(allOf(
1966                 withText(workResolvedComponentInfos.get(0)
1967                         .getResolveInfoAt(0).activityInfo.applicationInfo.name),
1968                 isDisplayed())))
1969                 .perform(click());
1970         waitForIdle();
1971         assertThat(chosen[0], is(workResolvedComponentInfos.get(0).getResolveInfoAt(0)));
1972     }
1973 
1974     @Test
testWorkTab_crossProfileIntentsDisabled_personalToWork_emptyStateShown()1975     public void testWorkTab_crossProfileIntentsDisabled_personalToWork_emptyStateShown() {
1976         // enable the work tab feature flag
1977         ResolverActivity.ENABLE_TABBED_VIEW = true;
1978         markWorkProfileUserAvailable();
1979         int workProfileTargets = 4;
1980         List<ResolvedComponentInfo> personalResolvedComponentInfos =
1981                 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
1982         List<ResolvedComponentInfo> workResolvedComponentInfos =
1983                 createResolvedComponentsForTest(workProfileTargets);
1984         ChooserActivityOverrideData.getInstance().hasCrossProfileIntents = false;
1985         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
1986         Intent sendIntent = createSendTextIntent();
1987         sendIntent.setType(TEST_MIME_TYPE);
1988 
1989         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
1990         waitForIdle();
1991         onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
1992         waitForIdle();
1993         onView(withIdFromRuntimeResource("contentPanel"))
1994                 .perform(swipeUp());
1995 
1996         onView(withTextFromRuntimeResource("resolver_cross_profile_blocked"))
1997                 .check(matches(isDisplayed()));
1998     }
1999 
2000     @Test
testWorkTab_workProfileDisabled_emptyStateShown()2001     public void testWorkTab_workProfileDisabled_emptyStateShown() {
2002         // enable the work tab feature flag
2003         markWorkProfileUserAvailable();
2004         int workProfileTargets = 4;
2005         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2006                 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
2007         List<ResolvedComponentInfo> workResolvedComponentInfos =
2008                 createResolvedComponentsForTest(workProfileTargets);
2009         ChooserActivityOverrideData.getInstance().isQuietModeEnabled = true;
2010         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
2011         Intent sendIntent = createSendTextIntent();
2012         sendIntent.setType(TEST_MIME_TYPE);
2013 
2014         ResolverActivity.ENABLE_TABBED_VIEW = true;
2015         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
2016         waitForIdle();
2017         onView(withIdFromRuntimeResource("contentPanel"))
2018                 .perform(swipeUp());
2019         onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
2020         waitForIdle();
2021 
2022         onView(withTextFromRuntimeResource("resolver_turn_on_work_apps"))
2023                 .check(matches(isDisplayed()));
2024     }
2025 
2026     @Test
testWorkTab_noWorkAppsAvailable_emptyStateShown()2027     public void testWorkTab_noWorkAppsAvailable_emptyStateShown() {
2028         // enable the work tab feature flag
2029         ResolverActivity.ENABLE_TABBED_VIEW = true;
2030         markWorkProfileUserAvailable();
2031         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2032                 createResolvedComponentsForTest(3);
2033         List<ResolvedComponentInfo> workResolvedComponentInfos =
2034                 createResolvedComponentsForTest(0);
2035         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
2036         Intent sendIntent = createSendTextIntent();
2037         sendIntent.setType(TEST_MIME_TYPE);
2038 
2039         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
2040         waitForIdle();
2041         onView(withIdFromRuntimeResource("contentPanel"))
2042                 .perform(swipeUp());
2043         onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
2044         waitForIdle();
2045 
2046         onView(withTextFromRuntimeResource("resolver_no_work_apps_available"))
2047                 .check(matches(isDisplayed()));
2048     }
2049 
2050     @Ignore // b/220067877
2051     @Test
testWorkTab_xProfileOff_noAppsAvailable_workOff_xProfileOffEmptyStateShown()2052     public void testWorkTab_xProfileOff_noAppsAvailable_workOff_xProfileOffEmptyStateShown() {
2053         // enable the work tab feature flag
2054         ResolverActivity.ENABLE_TABBED_VIEW = true;
2055         markWorkProfileUserAvailable();
2056         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2057                 createResolvedComponentsForTest(3);
2058         List<ResolvedComponentInfo> workResolvedComponentInfos =
2059                 createResolvedComponentsForTest(0);
2060         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
2061         ChooserActivityOverrideData.getInstance().isQuietModeEnabled = true;
2062         ChooserActivityOverrideData.getInstance().hasCrossProfileIntents = false;
2063         Intent sendIntent = createSendTextIntent();
2064         sendIntent.setType(TEST_MIME_TYPE);
2065 
2066         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
2067         waitForIdle();
2068         onView(withIdFromRuntimeResource("contentPanel"))
2069                 .perform(swipeUp());
2070         onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
2071         waitForIdle();
2072 
2073         onView(withTextFromRuntimeResource("resolver_cross_profile_blocked"))
2074                 .check(matches(isDisplayed()));
2075     }
2076 
2077     @Test
testWorkTab_noAppsAvailable_workOff_noAppsAvailableEmptyStateShown()2078     public void testWorkTab_noAppsAvailable_workOff_noAppsAvailableEmptyStateShown() {
2079         // enable the work tab feature flag
2080         ResolverActivity.ENABLE_TABBED_VIEW = true;
2081         markWorkProfileUserAvailable();
2082         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2083                 createResolvedComponentsForTest(3);
2084         List<ResolvedComponentInfo> workResolvedComponentInfos =
2085                 createResolvedComponentsForTest(0);
2086         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
2087         ChooserActivityOverrideData.getInstance().isQuietModeEnabled = true;
2088         Intent sendIntent = createSendTextIntent();
2089         sendIntent.setType(TEST_MIME_TYPE);
2090 
2091         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
2092         waitForIdle();
2093         onView(withIdFromRuntimeResource("contentPanel"))
2094                 .perform(swipeUp());
2095         onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
2096         waitForIdle();
2097 
2098         onView(withTextFromRuntimeResource("resolver_no_work_apps_available"))
2099                 .check(matches(isDisplayed()));
2100     }
2101 
2102     @Test @Ignore("b/222124533")
testAppTargetLogging()2103     public void testAppTargetLogging() throws InterruptedException {
2104         Intent sendIntent = createSendTextIntent();
2105         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
2106 
2107         when(
2108                 ChooserActivityOverrideData
2109                         .getInstance()
2110                         .resolverListController
2111                         .getResolversForIntent(
2112                                 Mockito.anyBoolean(),
2113                                 Mockito.anyBoolean(),
2114                                 Mockito.anyBoolean(),
2115                                 Mockito.isA(List.class)))
2116                 .thenReturn(resolvedComponentInfos);
2117 
2118         final IChooserWrapper activity = (IChooserWrapper)
2119                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
2120         waitForIdle();
2121 
2122         // TODO(b/222124533): other test cases use a timeout to make sure that the UI is fully
2123         // populated; without one, this test flakes. Ideally we should address the need for a
2124         // timeout everywhere instead of introducing one to fix this particular test.
2125 
2126         assertThat(activity.getAdapter().getCount(), is(2));
2127         onView(withIdFromRuntimeResource("profile_button")).check(doesNotExist());
2128 
2129         ResolveInfo[] chosen = new ResolveInfo[1];
2130         ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
2131             chosen[0] = targetInfo.getResolveInfo();
2132             return true;
2133         };
2134 
2135         ResolveInfo toChoose = resolvedComponentInfos.get(0).getResolveInfoAt(0);
2136         onView(withText(toChoose.activityInfo.name))
2137                 .perform(click());
2138         waitForIdle();
2139 
2140         ChooserActivityLoggerFake logger =
2141                 (ChooserActivityLoggerFake) activity.getChooserActivityLogger();
2142 
2143         // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events.
2144         logger.removeCallsForUiEventsOfType(
2145                 ChooserActivityLogger.SharesheetStandardEvent
2146                         .SHARESHEET_DIRECT_LOAD_COMPLETE.getId());
2147 
2148         // SHARESHEET_TRIGGERED:
2149         assertThat(logger.event(0).getId(),
2150                 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId()));
2151 
2152         // SHARESHEET_STARTED:
2153         assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED));
2154         assertThat(logger.get(1).intent, is(Intent.ACTION_SEND));
2155         assertThat(logger.get(1).mimeType, is("text/plain"));
2156         assertThat(logger.get(1).packageName, is(
2157                 InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName()));
2158         assertThat(logger.get(1).appProvidedApp, is(0));
2159         assertThat(logger.get(1).appProvidedDirect, is(0));
2160         assertThat(logger.get(1).isWorkprofile, is(false));
2161         assertThat(logger.get(1).previewType, is(3));
2162 
2163         // SHARESHEET_APP_LOAD_COMPLETE:
2164         assertThat(logger.event(2).getId(),
2165                 is(ChooserActivityLogger
2166                         .SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId()));
2167 
2168         // Next are just artifacts of test set-up:
2169         assertThat(logger.event(3).getId(),
2170                 is(ChooserActivityLogger
2171                         .SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId()));
2172         assertThat(logger.event(4).getId(),
2173                 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_EXPANDED.getId()));
2174 
2175         // SHARESHEET_APP_TARGET_SELECTED:
2176         assertThat(logger.get(5).atomId, is(FrameworkStatsLog.RANKING_SELECTED));
2177         assertThat(logger.get(5).targetType,
2178                 is(ChooserActivityLogger
2179                         .SharesheetTargetSelectedEvent.SHARESHEET_APP_TARGET_SELECTED.getId()));
2180 
2181         // No more events.
2182         assertThat(logger.numCalls(), is(6));
2183     }
2184 
2185     @Test
testDirectTargetLogging()2186     public void testDirectTargetLogging() {
2187         Intent sendIntent = createSendTextIntent();
2188         // We need app targets for direct targets to get displayed
2189         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
2190         when(
2191                 ChooserActivityOverrideData
2192                         .getInstance()
2193                         .resolverListController
2194                         .getResolversForIntent(
2195                                 Mockito.anyBoolean(),
2196                                 Mockito.anyBoolean(),
2197                                 Mockito.anyBoolean(),
2198                                 Mockito.isA(List.class)))
2199                 .thenReturn(resolvedComponentInfos);
2200 
2201         // Create direct share target
2202         List<ChooserTarget> serviceTargets = createDirectShareTargets(1,
2203                 resolvedComponentInfos.get(0).getResolveInfoAt(0).activityInfo.packageName);
2204         ResolveInfo ri = ResolverDataProvider.createResolveInfo(3, 0,
2205                 PERSONAL_USER_HANDLE);
2206 
2207         ChooserActivityOverrideData
2208                 .getInstance()
2209                 .directShareTargets = (activity, adapter) -> {
2210                     DisplayResolveInfo displayInfo = activity.createTestDisplayResolveInfo(
2211                             sendIntent,
2212                             ri,
2213                              "testLabel",
2214                              "testInfo",
2215                             sendIntent,
2216                             /* resolveInfoPresentationGetter */ null);
2217                     ServiceResultInfo[] results = {
2218                             new ServiceResultInfo(
2219                                     displayInfo,
2220                                     serviceTargets,
2221                                     adapter.getUserHandle())};
2222                     // TODO: consider covering the other type.
2223                     //  Only 2 types are expected out of the shortcut loading logic:
2224                     //  - TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER, if shortcuts were loaded from
2225                     //    the ShortcutManager, and;
2226                     //  - TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE, if shortcuts were loaded
2227                     //    from AppPredictor.
2228                     //  Ideally, our tests should cover all of them.
2229                     return new Pair<>(TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER, results);
2230                 };
2231 
2232         // Start activity
2233         final IChooserWrapper activity = (IChooserWrapper)
2234                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
2235 
2236         assertThat("Chooser should have 3 targets (2 apps, 1 direct)",
2237                 activity.getAdapter().getCount(), is(3));
2238         assertThat("Chooser should have exactly one selectable direct target",
2239                 activity.getAdapter().getSelectableServiceTargetCount(), is(1));
2240         assertThat("The resolver info must match the resolver info used to create the target",
2241                 activity.getAdapter().getItem(0).getResolveInfo(), is(ri));
2242 
2243         // Click on the direct target
2244         String name = serviceTargets.get(0).getTitle().toString();
2245         onView(withText(name))
2246                 .perform(click());
2247         waitForIdle();
2248 
2249         ChooserActivityLoggerFake logger =
2250                 (ChooserActivityLoggerFake) activity.getChooserActivityLogger();
2251         assertThat(logger.numCalls(), is(6));
2252         // first one should be SHARESHEET_TRIGGERED uievent
2253         assertThat(logger.get(0).atomId, is(FrameworkStatsLog.UI_EVENT_REPORTED));
2254         assertThat(logger.get(0).event.getId(),
2255                 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId()));
2256         // second one should be SHARESHEET_STARTED event
2257         assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED));
2258         assertThat(logger.get(1).intent, is(Intent.ACTION_SEND));
2259         assertThat(logger.get(1).mimeType, is("text/plain"));
2260         assertThat(logger.get(1).packageName, is(
2261                 InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName()));
2262         assertThat(logger.get(1).appProvidedApp, is(0));
2263         assertThat(logger.get(1).appProvidedDirect, is(0));
2264         assertThat(logger.get(1).isWorkprofile, is(false));
2265         assertThat(logger.get(1).previewType, is(3));
2266         // third one should be SHARESHEET_APP_LOAD_COMPLETE uievent
2267         assertThat(logger.get(2).atomId, is(FrameworkStatsLog.UI_EVENT_REPORTED));
2268         assertThat(logger.get(2).event.getId(),
2269                 is(ChooserActivityLogger
2270                         .SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId()));
2271         // fourth and fifth are just artifacts of test set-up
2272         // sixth one should be ranking atom with SHARESHEET_COPY_TARGET_SELECTED event
2273         assertThat(logger.get(5).atomId, is(FrameworkStatsLog.RANKING_SELECTED));
2274         assertThat(logger.get(5).targetType,
2275                 is(ChooserActivityLogger
2276                         .SharesheetTargetSelectedEvent.SHARESHEET_SERVICE_TARGET_SELECTED.getId()));
2277     }
2278 
2279     @Test @Ignore
testEmptyDirectRowLogging()2280     public void testEmptyDirectRowLogging() throws InterruptedException {
2281         Intent sendIntent = createSendTextIntent();
2282         // We need app targets for direct targets to get displayed
2283         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
2284         when(
2285                 ChooserActivityOverrideData
2286                         .getInstance()
2287                         .resolverListController
2288                         .getResolversForIntent(
2289                                 Mockito.anyBoolean(),
2290                                 Mockito.anyBoolean(),
2291                                 Mockito.anyBoolean(),
2292                                 Mockito.isA(List.class)))
2293                 .thenReturn(resolvedComponentInfos);
2294 
2295         // Start activity
2296         final IChooserWrapper activity = (IChooserWrapper)
2297                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
2298 
2299         // Thread.sleep shouldn't be a thing in an integration test but it's
2300         // necessary here because of the way the code is structured
2301         Thread.sleep(3000);
2302 
2303         assertThat("Chooser should have 2 app targets",
2304                 activity.getAdapter().getCount(), is(2));
2305         assertThat("Chooser should have no direct targets",
2306                 activity.getAdapter().getSelectableServiceTargetCount(), is(0));
2307 
2308         ChooserActivityLoggerFake logger =
2309                 (ChooserActivityLoggerFake) activity.getChooserActivityLogger();
2310 
2311         // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events.
2312         logger.removeCallsForUiEventsOfType(
2313                 ChooserActivityLogger.SharesheetStandardEvent
2314                         .SHARESHEET_DIRECT_LOAD_COMPLETE.getId());
2315 
2316         // SHARESHEET_TRIGGERED:
2317         assertThat(logger.event(0).getId(),
2318                 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId()));
2319 
2320         // SHARESHEET_STARTED:
2321         assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED));
2322         assertThat(logger.get(1).intent, is(Intent.ACTION_SEND));
2323         assertThat(logger.get(1).mimeType, is("text/plain"));
2324         assertThat(logger.get(1).packageName, is(
2325                 InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName()));
2326         assertThat(logger.get(1).appProvidedApp, is(0));
2327         assertThat(logger.get(1).appProvidedDirect, is(0));
2328         assertThat(logger.get(1).isWorkprofile, is(false));
2329         assertThat(logger.get(1).previewType, is(3));
2330 
2331         // SHARESHEET_APP_LOAD_COMPLETE:
2332         assertThat(logger.event(2).getId(),
2333                 is(ChooserActivityLogger
2334                         .SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId()));
2335 
2336         // SHARESHEET_EMPTY_DIRECT_SHARE_ROW:
2337         assertThat(logger.event(3).getId(),
2338                 is(ChooserActivityLogger
2339                         .SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId()));
2340 
2341         // Next is just an artifact of test set-up:
2342         assertThat(logger.event(4).getId(),
2343                 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_EXPANDED.getId()));
2344 
2345         assertThat(logger.numCalls(), is(5));
2346     }
2347 
2348     @Ignore // b/220067877
2349     @Test
testCopyTextToClipboardLogging()2350     public void testCopyTextToClipboardLogging() throws Exception {
2351         Intent sendIntent = createSendTextIntent();
2352         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
2353 
2354         when(
2355                 ChooserActivityOverrideData
2356                         .getInstance()
2357                         .resolverListController
2358                         .getResolversForIntent(
2359                                 Mockito.anyBoolean(),
2360                                 Mockito.anyBoolean(),
2361                                 Mockito.anyBoolean(),
2362                                 Mockito.isA(List.class)))
2363                 .thenReturn(resolvedComponentInfos);
2364 
2365         final IChooserWrapper activity = (IChooserWrapper)
2366                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
2367         waitForIdle();
2368 
2369         onView(withIdFromRuntimeResource("chooser_copy_button")).check(matches(isDisplayed()));
2370         onView(withIdFromRuntimeResource("chooser_copy_button")).perform(click());
2371 
2372         ChooserActivityLoggerFake logger =
2373                 (ChooserActivityLoggerFake) activity.getChooserActivityLogger();
2374 
2375         // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events.
2376         logger.removeCallsForUiEventsOfType(
2377                 ChooserActivityLogger.SharesheetStandardEvent
2378                         .SHARESHEET_DIRECT_LOAD_COMPLETE.getId());
2379 
2380         // SHARESHEET_TRIGGERED:
2381         assertThat(logger.event(0).getId(),
2382                 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId()));
2383 
2384         // SHARESHEET_STARTED:
2385         assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED));
2386         assertThat(logger.get(1).intent, is(Intent.ACTION_SEND));
2387         assertThat(logger.get(1).mimeType, is("text/plain"));
2388         assertThat(logger.get(1).packageName, is(
2389                 InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName()));
2390         assertThat(logger.get(1).appProvidedApp, is(0));
2391         assertThat(logger.get(1).appProvidedDirect, is(0));
2392         assertThat(logger.get(1).isWorkprofile, is(false));
2393         assertThat(logger.get(1).previewType, is(3));
2394 
2395         // SHARESHEET_APP_LOAD_COMPLETE:
2396         assertThat(logger.event(2).getId(),
2397                 is(ChooserActivityLogger
2398                         .SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId()));
2399 
2400         // Next are just artifacts of test set-up:
2401         assertThat(logger.event(3).getId(),
2402                 is(ChooserActivityLogger
2403                         .SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId()));
2404         assertThat(logger.event(4).getId(),
2405                 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_EXPANDED.getId()));
2406 
2407         // SHARESHEET_COPY_TARGET_SELECTED:
2408         assertThat(logger.get(5).atomId, is(FrameworkStatsLog.RANKING_SELECTED));
2409         assertThat(logger.get(5).targetType,
2410                 is(ChooserActivityLogger
2411                         .SharesheetTargetSelectedEvent.SHARESHEET_COPY_TARGET_SELECTED.getId()));
2412 
2413         // No more events.
2414         assertThat(logger.numCalls(), is(6));
2415     }
2416 
2417     @Test @Ignore("b/222124533")
testSwitchProfileLogging()2418     public void testSwitchProfileLogging() throws InterruptedException {
2419         // enable the work tab feature flag
2420         ResolverActivity.ENABLE_TABBED_VIEW = true;
2421         markWorkProfileUserAvailable();
2422         int workProfileTargets = 4;
2423         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2424                 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
2425         List<ResolvedComponentInfo> workResolvedComponentInfos =
2426                 createResolvedComponentsForTest(workProfileTargets);
2427         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
2428         Intent sendIntent = createSendTextIntent();
2429         sendIntent.setType(TEST_MIME_TYPE);
2430 
2431         final IChooserWrapper activity = (IChooserWrapper)
2432                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
2433         waitForIdle();
2434         onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
2435         waitForIdle();
2436         onView(withTextFromRuntimeResource("resolver_personal_tab")).perform(click());
2437         waitForIdle();
2438 
2439         ChooserActivityLoggerFake logger =
2440                 (ChooserActivityLoggerFake) activity.getChooserActivityLogger();
2441 
2442         // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events.
2443         logger.removeCallsForUiEventsOfType(
2444                 ChooserActivityLogger.SharesheetStandardEvent
2445                         .SHARESHEET_DIRECT_LOAD_COMPLETE.getId());
2446 
2447         // SHARESHEET_TRIGGERED:
2448         assertThat(logger.event(0).getId(),
2449                 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId()));
2450 
2451         // SHARESHEET_STARTED:
2452         assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED));
2453         assertThat(logger.get(1).intent, is(Intent.ACTION_SEND));
2454         assertThat(logger.get(1).mimeType, is(TEST_MIME_TYPE));
2455         assertThat(logger.get(1).packageName, is(
2456                 InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName()));
2457         assertThat(logger.get(1).appProvidedApp, is(0));
2458         assertThat(logger.get(1).appProvidedDirect, is(0));
2459         assertThat(logger.get(1).isWorkprofile, is(false));
2460         assertThat(logger.get(1).previewType, is(3));
2461 
2462         // SHARESHEET_APP_LOAD_COMPLETE:
2463         assertThat(logger.event(2).getId(),
2464                 is(ChooserActivityLogger
2465                         .SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId()));
2466 
2467         // Next is just an artifact of test set-up:
2468         assertThat(logger.event(3).getId(),
2469                 is(ChooserActivityLogger
2470                         .SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId()));
2471 
2472         // SHARESHEET_PROFILE_CHANGED:
2473         assertThat(logger.event(4).getId(),
2474                 is(ChooserActivityLogger.SharesheetStandardEvent
2475                         .SHARESHEET_PROFILE_CHANGED.getId()));
2476 
2477         // Repeat the loading steps in the new profile:
2478 
2479         // SHARESHEET_APP_LOAD_COMPLETE:
2480         assertThat(logger.event(5).getId(),
2481                 is(ChooserActivityLogger
2482                         .SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId()));
2483 
2484         // Next is again an artifact of test set-up:
2485         assertThat(logger.event(6).getId(),
2486                 is(ChooserActivityLogger
2487                         .SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId()));
2488 
2489         // SHARESHEET_PROFILE_CHANGED:
2490         assertThat(logger.event(7).getId(),
2491                 is(ChooserActivityLogger.SharesheetStandardEvent
2492                         .SHARESHEET_PROFILE_CHANGED.getId()));
2493 
2494         // No more events (this profile was already loaded).
2495         assertThat(logger.numCalls(), is(8));
2496     }
2497 
2498     @Test
testAutolaunch_singleTarget_wifthWorkProfileAndTabbedViewOff_noAutolaunch()2499     public void testAutolaunch_singleTarget_wifthWorkProfileAndTabbedViewOff_noAutolaunch() {
2500         ResolverActivity.ENABLE_TABBED_VIEW = false;
2501         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2502                 createResolvedComponentsForTestWithOtherProfile(2, /* userId */ 10);
2503         when(
2504                 ChooserActivityOverrideData
2505                         .getInstance()
2506                         .resolverListController
2507                         .getResolversForIntent(
2508                                 Mockito.anyBoolean(),
2509                                 Mockito.anyBoolean(),
2510                                 Mockito.anyBoolean(),
2511                                 Mockito.isA(List.class)))
2512                 .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
2513         Intent sendIntent = createSendTextIntent();
2514         sendIntent.setType(TEST_MIME_TYPE);
2515         ResolveInfo[] chosen = new ResolveInfo[1];
2516         ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
2517             chosen[0] = targetInfo.getResolveInfo();
2518             return true;
2519         };
2520         waitForIdle();
2521 
2522         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
2523         waitForIdle();
2524 
2525         assertTrue(chosen[0] == null);
2526     }
2527 
2528     @Test
testAutolaunch_singleTarget_noWorkProfile_autolaunch()2529     public void testAutolaunch_singleTarget_noWorkProfile_autolaunch() {
2530         ResolverActivity.ENABLE_TABBED_VIEW = false;
2531         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2532                 createResolvedComponentsForTest(1);
2533         when(
2534                 ChooserActivityOverrideData
2535                         .getInstance()
2536                         .resolverListController
2537                         .getResolversForIntent(
2538                                 Mockito.anyBoolean(),
2539                                 Mockito.anyBoolean(),
2540                                 Mockito.anyBoolean(),
2541                                 Mockito.isA(List.class)))
2542                 .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
2543         Intent sendIntent = createSendTextIntent();
2544         sendIntent.setType(TEST_MIME_TYPE);
2545         ResolveInfo[] chosen = new ResolveInfo[1];
2546         ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
2547             chosen[0] = targetInfo.getResolveInfo();
2548             return true;
2549         };
2550         waitForIdle();
2551 
2552         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
2553         waitForIdle();
2554 
2555         assertThat(chosen[0], is(personalResolvedComponentInfos.get(0).getResolveInfoAt(0)));
2556     }
2557 
2558     @Test
testWorkTab_onePersonalTarget_emptyStateOnWorkTarget_autolaunch()2559     public void testWorkTab_onePersonalTarget_emptyStateOnWorkTarget_autolaunch() {
2560         // enable the work tab feature flag
2561         ResolverActivity.ENABLE_TABBED_VIEW = true;
2562         markWorkProfileUserAvailable();
2563         int workProfileTargets = 4;
2564         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2565                 createResolvedComponentsForTestWithOtherProfile(2, /* userId */ 10);
2566         List<ResolvedComponentInfo> workResolvedComponentInfos =
2567                 createResolvedComponentsForTest(workProfileTargets);
2568         ChooserActivityOverrideData.getInstance().hasCrossProfileIntents = false;
2569         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
2570         Intent sendIntent = createSendTextIntent();
2571         ResolveInfo[] chosen = new ResolveInfo[1];
2572         ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
2573             chosen[0] = targetInfo.getResolveInfo();
2574             return true;
2575         };
2576 
2577         mActivityRule.launchActivity(sendIntent);
2578         waitForIdle();
2579 
2580         assertThat(chosen[0], is(personalResolvedComponentInfos.get(1).getResolveInfoAt(0)));
2581     }
2582 
2583     @Test
testOneInitialIntent_noAutolaunch()2584     public void testOneInitialIntent_noAutolaunch() {
2585         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2586                 createResolvedComponentsForTest(1);
2587         when(
2588                 ChooserActivityOverrideData
2589                         .getInstance()
2590                         .resolverListController
2591                         .getResolversForIntent(
2592                                 Mockito.anyBoolean(),
2593                                 Mockito.anyBoolean(),
2594                                 Mockito.anyBoolean(),
2595                                 Mockito.isA(List.class)))
2596                 .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
2597         Intent chooserIntent = createChooserIntent(createSendTextIntent(),
2598                 new Intent[] {new Intent("action.fake")});
2599         ResolveInfo[] chosen = new ResolveInfo[1];
2600         ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
2601             chosen[0] = targetInfo.getResolveInfo();
2602             return true;
2603         };
2604         ChooserActivityOverrideData.getInstance().packageManager = mock(PackageManager.class);
2605         ResolveInfo ri = createFakeResolveInfo();
2606         when(
2607                 ChooserActivityOverrideData
2608                         .getInstance().packageManager
2609                         .resolveActivity(any(Intent.class), anyInt()))
2610                 .thenReturn(ri);
2611         waitForIdle();
2612 
2613         IChooserWrapper activity = (IChooserWrapper) mActivityRule.launchActivity(chooserIntent);
2614         waitForIdle();
2615 
2616         assertNull(chosen[0]);
2617         assertThat(activity
2618                 .getPersonalListAdapter().getCallerTargetCount(), is(1));
2619     }
2620 
2621     @Test
testWorkTab_withInitialIntents_workTabDoesNotIncludePersonalInitialIntents()2622     public void testWorkTab_withInitialIntents_workTabDoesNotIncludePersonalInitialIntents() {
2623         // enable the work tab feature flag
2624         ResolverActivity.ENABLE_TABBED_VIEW = true;
2625         markWorkProfileUserAvailable();
2626         int workProfileTargets = 1;
2627         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2628                 createResolvedComponentsForTestWithOtherProfile(2, /* userId */ 10);
2629         List<ResolvedComponentInfo> workResolvedComponentInfos =
2630                 createResolvedComponentsForTest(workProfileTargets);
2631         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
2632         Intent[] initialIntents = {
2633                 new Intent("action.fake1"),
2634                 new Intent("action.fake2")
2635         };
2636         Intent chooserIntent = createChooserIntent(createSendTextIntent(), initialIntents);
2637         ChooserActivityOverrideData.getInstance().packageManager = mock(PackageManager.class);
2638         when(
2639                 ChooserActivityOverrideData
2640                         .getInstance()
2641                         .packageManager
2642                         .resolveActivity(any(Intent.class), anyInt()))
2643                 .thenReturn(createFakeResolveInfo());
2644         waitForIdle();
2645 
2646         IChooserWrapper activity = (IChooserWrapper) mActivityRule.launchActivity(chooserIntent);
2647         waitForIdle();
2648 
2649         assertThat(activity.getPersonalListAdapter().getCallerTargetCount(), is(2));
2650         assertThat(activity.getWorkListAdapter().getCallerTargetCount(), is(0));
2651     }
2652 
2653     @Test
testWorkTab_xProfileIntentsDisabled_personalToWork_nonSendIntent_emptyStateShown()2654     public void testWorkTab_xProfileIntentsDisabled_personalToWork_nonSendIntent_emptyStateShown() {
2655         // enable the work tab feature flag
2656         ResolverActivity.ENABLE_TABBED_VIEW = true;
2657         markWorkProfileUserAvailable();
2658         int workProfileTargets = 4;
2659         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2660                 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
2661         List<ResolvedComponentInfo> workResolvedComponentInfos =
2662                 createResolvedComponentsForTest(workProfileTargets);
2663         ChooserActivityOverrideData.getInstance().hasCrossProfileIntents = false;
2664         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
2665         Intent[] initialIntents = {
2666                 new Intent("action.fake1"),
2667                 new Intent("action.fake2")
2668         };
2669         Intent chooserIntent = createChooserIntent(new Intent(), initialIntents);
2670         ChooserActivityOverrideData.getInstance().packageManager = mock(PackageManager.class);
2671         when(
2672                 ChooserActivityOverrideData
2673                         .getInstance()
2674                         .packageManager
2675                         .resolveActivity(any(Intent.class), anyInt()))
2676                 .thenReturn(createFakeResolveInfo());
2677 
2678         mActivityRule.launchActivity(chooserIntent);
2679         waitForIdle();
2680         onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
2681         waitForIdle();
2682         onView(withIdFromRuntimeResource("contentPanel"))
2683                 .perform(swipeUp());
2684 
2685         onView(withTextFromRuntimeResource("resolver_cross_profile_blocked"))
2686                 .check(matches(isDisplayed()));
2687     }
2688 
2689     @Test
testWorkTab_noWorkAppsAvailable_nonSendIntent_emptyStateShown()2690     public void testWorkTab_noWorkAppsAvailable_nonSendIntent_emptyStateShown() {
2691         // enable the work tab feature flag
2692         ResolverActivity.ENABLE_TABBED_VIEW = true;
2693         markWorkProfileUserAvailable();
2694         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2695                 createResolvedComponentsForTest(3);
2696         List<ResolvedComponentInfo> workResolvedComponentInfos =
2697                 createResolvedComponentsForTest(0);
2698         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
2699         Intent[] initialIntents = {
2700                 new Intent("action.fake1"),
2701                 new Intent("action.fake2")
2702         };
2703         Intent chooserIntent = createChooserIntent(new Intent(), initialIntents);
2704         ChooserActivityOverrideData.getInstance().packageManager = mock(PackageManager.class);
2705         when(
2706                 ChooserActivityOverrideData
2707                         .getInstance()
2708                         .packageManager
2709                         .resolveActivity(any(Intent.class), anyInt()))
2710                 .thenReturn(createFakeResolveInfo());
2711 
2712         mActivityRule.launchActivity(chooserIntent);
2713         waitForIdle();
2714         onView(withIdFromRuntimeResource("contentPanel"))
2715                 .perform(swipeUp());
2716         onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
2717         waitForIdle();
2718 
2719         onView(withTextFromRuntimeResource("resolver_no_work_apps_available"))
2720                 .check(matches(isDisplayed()));
2721     }
2722 
2723     @Test
testDeduplicateCallerTargetRankedTarget()2724     public void testDeduplicateCallerTargetRankedTarget() {
2725         // Create 4 ranked app targets.
2726         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2727                 createResolvedComponentsForTest(4);
2728         when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent(
2729                 Mockito.anyBoolean(),
2730                                 Mockito.anyBoolean(),
2731                                 Mockito.anyBoolean(),
2732                                 Mockito.isA(List.class)))
2733                 .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
2734         // Create caller target which is duplicate with one of app targets
2735         Intent chooserIntent = createChooserIntent(createSendTextIntent(),
2736                 new Intent[] {new Intent("action.fake")});
2737         ChooserActivityOverrideData.getInstance().packageManager = mock(PackageManager.class);
2738         ResolveInfo ri = ResolverDataProvider.createResolveInfo(0,
2739                 UserHandle.USER_CURRENT, PERSONAL_USER_HANDLE);
2740         when(
2741                 ChooserActivityOverrideData
2742                         .getInstance()
2743                         .packageManager
2744                         .resolveActivity(any(Intent.class), anyInt()))
2745                 .thenReturn(ri);
2746         waitForIdle();
2747 
2748         IChooserWrapper activity = (IChooserWrapper) mActivityRule.launchActivity(chooserIntent);
2749         waitForIdle();
2750 
2751         // Total 4 targets (1 caller target, 3 ranked targets)
2752         assertThat(activity.getAdapter().getCount(), is(4));
2753         assertThat(activity.getAdapter().getCallerTargetCount(), is(1));
2754         assertThat(activity.getAdapter().getRankedTargetCount(), is(3));
2755     }
2756 
2757     @Test
testWorkTab_selectingWorkTabWithPausedWorkProfile_directShareTargetsNotQueried()2758     public void testWorkTab_selectingWorkTabWithPausedWorkProfile_directShareTargetsNotQueried() {
2759         // enable the work tab feature flag
2760         ResolverActivity.ENABLE_TABBED_VIEW = true;
2761         markWorkProfileUserAvailable();
2762         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2763                 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
2764         List<ResolvedComponentInfo> workResolvedComponentInfos =
2765                 createResolvedComponentsForTest(3);
2766         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
2767         ChooserActivityOverrideData.getInstance().isQuietModeEnabled = true;
2768         boolean[] isQueryDirectShareCalledOnWorkProfile = new boolean[] { false };
2769         ChooserActivityOverrideData.getInstance().onQueryDirectShareTargets =
2770                 chooserListAdapter -> {
2771                     isQueryDirectShareCalledOnWorkProfile[0] =
2772                             (chooserListAdapter.getUserHandle().getIdentifier() == 10);
2773                     return null;
2774                 };
2775         Intent sendIntent = createSendTextIntent();
2776         sendIntent.setType(TEST_MIME_TYPE);
2777 
2778         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
2779         waitForIdle();
2780         onView(withIdFromRuntimeResource("contentPanel"))
2781                 .perform(swipeUp());
2782         onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
2783         waitForIdle();
2784 
2785         assertFalse("Direct share targets were queried on a paused work profile",
2786                 isQueryDirectShareCalledOnWorkProfile[0]);
2787     }
2788 
2789     @Test
testWorkTab_selectingWorkTabWithNotRunningWorkUser_directShareTargetsNotQueried()2790     public void testWorkTab_selectingWorkTabWithNotRunningWorkUser_directShareTargetsNotQueried() {
2791         // enable the work tab feature flag
2792         ResolverActivity.ENABLE_TABBED_VIEW = true;
2793         markWorkProfileUserAvailable();
2794         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2795                 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
2796         List<ResolvedComponentInfo> workResolvedComponentInfos =
2797                 createResolvedComponentsForTest(3);
2798         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
2799         ChooserActivityOverrideData.getInstance().isWorkProfileUserRunning = false;
2800         boolean[] isQueryDirectShareCalledOnWorkProfile = new boolean[] { false };
2801         ChooserActivityOverrideData.getInstance().onQueryDirectShareTargets =
2802                 chooserListAdapter -> {
2803                     isQueryDirectShareCalledOnWorkProfile[0] =
2804                             (chooserListAdapter.getUserHandle().getIdentifier() == 10);
2805                     return null;
2806                 };
2807         Intent sendIntent = createSendTextIntent();
2808         sendIntent.setType(TEST_MIME_TYPE);
2809 
2810         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
2811         waitForIdle();
2812         onView(withIdFromRuntimeResource("contentPanel"))
2813                 .perform(swipeUp());
2814         onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
2815         waitForIdle();
2816 
2817         assertFalse("Direct share targets were queried on a locked work profile user",
2818                 isQueryDirectShareCalledOnWorkProfile[0]);
2819     }
2820 
2821     @Test
testWorkTab_workUserNotRunning_workTargetsShown()2822     public void testWorkTab_workUserNotRunning_workTargetsShown() {
2823         // enable the work tab feature flag
2824         ResolverActivity.ENABLE_TABBED_VIEW = true;
2825         markWorkProfileUserAvailable();
2826         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2827                 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
2828         List<ResolvedComponentInfo> workResolvedComponentInfos =
2829                 createResolvedComponentsForTest(3);
2830         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
2831         Intent sendIntent = createSendTextIntent();
2832         sendIntent.setType(TEST_MIME_TYPE);
2833         ChooserActivityOverrideData.getInstance().isWorkProfileUserRunning = false;
2834 
2835         final ChooserActivity activity =
2836                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
2837         final IChooserWrapper wrapper = (IChooserWrapper) activity;
2838         waitForIdle();
2839         onView(withIdFromRuntimeResource("contentPanel")).perform(swipeUp());
2840         onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
2841         waitForIdle();
2842 
2843         assertEquals(3, wrapper.getWorkListAdapter().getCount());
2844     }
2845 
2846     @Test
testWorkTab_selectingWorkTabWithLockedWorkUser_directShareTargetsNotQueried()2847     public void testWorkTab_selectingWorkTabWithLockedWorkUser_directShareTargetsNotQueried() {
2848         // enable the work tab feature flag
2849         ResolverActivity.ENABLE_TABBED_VIEW = true;
2850         markWorkProfileUserAvailable();
2851         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2852                 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
2853         List<ResolvedComponentInfo> workResolvedComponentInfos =
2854                 createResolvedComponentsForTest(3);
2855         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
2856         ChooserActivityOverrideData.getInstance().isWorkProfileUserUnlocked = false;
2857         boolean[] isQueryDirectShareCalledOnWorkProfile = new boolean[] { false };
2858         ChooserActivityOverrideData.getInstance().onQueryDirectShareTargets =
2859                 chooserListAdapter -> {
2860                     isQueryDirectShareCalledOnWorkProfile[0] =
2861                             (chooserListAdapter.getUserHandle().getIdentifier() == 10);
2862                     return null;
2863                 };
2864         Intent sendIntent = createSendTextIntent();
2865         sendIntent.setType(TEST_MIME_TYPE);
2866 
2867         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
2868         waitForIdle();
2869         onView(withIdFromRuntimeResource("contentPanel"))
2870                 .perform(swipeUp());
2871         onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
2872         waitForIdle();
2873 
2874         assertFalse("Direct share targets were queried on a locked work profile user",
2875                 isQueryDirectShareCalledOnWorkProfile[0]);
2876     }
2877 
2878     @Test
testWorkTab_workUserLocked_workTargetsShown()2879     public void testWorkTab_workUserLocked_workTargetsShown() {
2880         // enable the work tab feature flag
2881         ResolverActivity.ENABLE_TABBED_VIEW = true;
2882         markWorkProfileUserAvailable();
2883         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2884                 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
2885         List<ResolvedComponentInfo> workResolvedComponentInfos =
2886                 createResolvedComponentsForTest(3);
2887         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
2888         Intent sendIntent = createSendTextIntent();
2889         sendIntent.setType(TEST_MIME_TYPE);
2890         ChooserActivityOverrideData.getInstance().isWorkProfileUserUnlocked = false;
2891 
2892         final ChooserActivity activity =
2893                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
2894         final IChooserWrapper wrapper = (IChooserWrapper) activity;
2895         waitForIdle();
2896         onView(withIdFromRuntimeResource("contentPanel"))
2897                 .perform(swipeUp());
2898         onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
2899         waitForIdle();
2900 
2901         assertEquals(3, wrapper.getWorkListAdapter().getCount());
2902     }
2903 
2904     @Test
testClonedProfilePresent_personalAdapterIsSetWithPersonalProfile()2905     public void testClonedProfilePresent_personalAdapterIsSetWithPersonalProfile() {
2906         // enable cloneProfile
2907         markCloneProfileUserAvailable();
2908         List<ResolvedComponentInfo> resolvedComponentInfos =
2909                 createResolvedComponentsWithCloneProfileForTest(
2910                         3,
2911                         PERSONAL_USER_HANDLE,
2912                         ChooserActivityOverrideData.getInstance().cloneProfileUserHandle);
2913         when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent(
2914                 Mockito.anyBoolean(),
2915                 Mockito.anyBoolean(),
2916                 Mockito.anyBoolean(),
2917                 Mockito.isA(List.class)))
2918                 .thenReturn(new ArrayList<>(resolvedComponentInfos));
2919         Intent sendIntent = createSendTextIntent();
2920 
2921         final IChooserWrapper activity = (IChooserWrapper) mActivityRule
2922                 .launchActivity(Intent.createChooser(sendIntent, "personalProfileTest"));
2923         waitForIdle();
2924 
2925         assertThat(activity.getPersonalListAdapter().getUserHandle(), is(PERSONAL_USER_HANDLE));
2926         assertThat(activity.getAdapter().getCount(), is(3));
2927     }
2928 
2929     @Test
testClonedProfilePresent_personalTabUsesExpectedAdapter()2930     public void testClonedProfilePresent_personalTabUsesExpectedAdapter() {
2931         // enable the work tab feature flag
2932         ResolverActivity.ENABLE_TABBED_VIEW = true;
2933         markWorkProfileUserAvailable();
2934         markCloneProfileUserAvailable();
2935         List<ResolvedComponentInfo> personalResolvedComponentInfos =
2936                 createResolvedComponentsForTest(3);
2937         List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(
2938                 4);
2939         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
2940         Intent sendIntent = createSendTextIntent();
2941         sendIntent.setType(TEST_MIME_TYPE);
2942 
2943 
2944         final IChooserWrapper activity = (IChooserWrapper)
2945                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "multi tab test"));
2946         waitForIdle();
2947 
2948         assertThat(activity.getCurrentUserHandle(), is(PERSONAL_USER_HANDLE));
2949     }
2950 
createChooserIntent(Intent intent, Intent[] initialIntents)2951     private Intent createChooserIntent(Intent intent, Intent[] initialIntents) {
2952         Intent chooserIntent = new Intent();
2953         chooserIntent.setAction(Intent.ACTION_CHOOSER);
2954         chooserIntent.putExtra(Intent.EXTRA_TEXT, "testing intent sending");
2955         chooserIntent.putExtra(Intent.EXTRA_TITLE, "some title");
2956         chooserIntent.putExtra(Intent.EXTRA_INTENT, intent);
2957         chooserIntent.setType("text/plain");
2958         if (initialIntents != null) {
2959             chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, initialIntents);
2960         }
2961         return chooserIntent;
2962     }
2963 
createFakeResolveInfo()2964     private ResolveInfo createFakeResolveInfo() {
2965         ResolveInfo ri = new ResolveInfo();
2966         ri.activityInfo = new ActivityInfo();
2967         ri.activityInfo.name = "FakeActivityName";
2968         ri.activityInfo.packageName = "fake.package.name";
2969         ri.activityInfo.applicationInfo = new ApplicationInfo();
2970         ri.activityInfo.applicationInfo.packageName = "fake.package.name";
2971         ri.userHandle = UserHandle.CURRENT;
2972         return ri;
2973     }
2974 
createSendTextIntent()2975     private Intent createSendTextIntent() {
2976         Intent sendIntent = new Intent();
2977         sendIntent.setAction(Intent.ACTION_SEND);
2978         sendIntent.putExtra(Intent.EXTRA_TEXT, "testing intent sending");
2979         sendIntent.setType("text/plain");
2980         return sendIntent;
2981     }
2982 
createSendImageIntent(Uri imageThumbnail)2983     private Intent createSendImageIntent(Uri imageThumbnail) {
2984         Intent sendIntent = new Intent();
2985         sendIntent.setAction(Intent.ACTION_SEND);
2986         sendIntent.putExtra(Intent.EXTRA_STREAM, imageThumbnail);
2987         sendIntent.setType("image/png");
2988         if (imageThumbnail != null) {
2989             ClipData.Item clipItem = new ClipData.Item(imageThumbnail);
2990             sendIntent.setClipData(new ClipData("Clip Label", new String[]{"image/png"}, clipItem));
2991         }
2992 
2993         return sendIntent;
2994     }
2995 
createSendTextIntentWithPreview(String title, Uri imageThumbnail)2996     private Intent createSendTextIntentWithPreview(String title, Uri imageThumbnail) {
2997         Intent sendIntent = new Intent();
2998         sendIntent.setAction(Intent.ACTION_SEND);
2999         sendIntent.putExtra(Intent.EXTRA_TEXT, "testing intent sending");
3000         sendIntent.putExtra(Intent.EXTRA_TITLE, title);
3001         if (imageThumbnail != null) {
3002             ClipData.Item clipItem = new ClipData.Item(imageThumbnail);
3003             sendIntent.setClipData(new ClipData("Clip Label", new String[]{"image/png"}, clipItem));
3004         }
3005 
3006         return sendIntent;
3007     }
3008 
createSendUriIntentWithPreview(ArrayList<Uri> uris)3009     private Intent createSendUriIntentWithPreview(ArrayList<Uri> uris) {
3010         Intent sendIntent = new Intent();
3011 
3012         if (uris.size() > 1) {
3013             sendIntent.setAction(Intent.ACTION_SEND_MULTIPLE);
3014             sendIntent.putExtra(Intent.EXTRA_STREAM, uris);
3015         } else {
3016             sendIntent.setAction(Intent.ACTION_SEND);
3017             sendIntent.putExtra(Intent.EXTRA_STREAM, uris.get(0));
3018         }
3019 
3020         return sendIntent;
3021     }
3022 
createViewTextIntent()3023     private Intent createViewTextIntent() {
3024         Intent viewIntent = new Intent();
3025         viewIntent.setAction(Intent.ACTION_VIEW);
3026         viewIntent.putExtra(Intent.EXTRA_TEXT, "testing intent viewing");
3027         return viewIntent;
3028     }
3029 
createResolvedComponentsForTest(int numberOfResults)3030     private List<ResolvedComponentInfo> createResolvedComponentsForTest(int numberOfResults) {
3031         List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
3032         for (int i = 0; i < numberOfResults; i++) {
3033             infoList.add(ResolverDataProvider.createResolvedComponentInfo(i, PERSONAL_USER_HANDLE));
3034         }
3035         return infoList;
3036     }
3037 
createResolvedComponentsWithCloneProfileForTest( int numberOfResults, UserHandle resolvedForPersonalUser, UserHandle resolvedForClonedUser)3038     private List<ResolvedComponentInfo> createResolvedComponentsWithCloneProfileForTest(
3039             int numberOfResults,
3040             UserHandle resolvedForPersonalUser,
3041             UserHandle resolvedForClonedUser) {
3042         List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
3043         for (int i = 0; i < 1; i++) {
3044             infoList.add(ResolverDataProvider.createResolvedComponentInfo(i,
3045                     resolvedForPersonalUser));
3046         }
3047         for (int i = 1; i < numberOfResults; i++) {
3048             infoList.add(ResolverDataProvider.createResolvedComponentInfo(i,
3049                     resolvedForClonedUser));
3050         }
3051         return infoList;
3052     }
3053 
createResolvedComponentsForTestWithOtherProfile( int numberOfResults)3054     private List<ResolvedComponentInfo> createResolvedComponentsForTestWithOtherProfile(
3055             int numberOfResults) {
3056         List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
3057         for (int i = 0; i < numberOfResults; i++) {
3058             if (i == 0) {
3059                 infoList.add(ResolverDataProvider.createResolvedComponentInfoWithOtherId(i,
3060                         PERSONAL_USER_HANDLE));
3061             } else {
3062                 infoList.add(ResolverDataProvider.createResolvedComponentInfo(i,
3063                         PERSONAL_USER_HANDLE));
3064             }
3065         }
3066         return infoList;
3067     }
3068 
createResolvedComponentsForTestWithOtherProfile( int numberOfResults, int userId)3069     private List<ResolvedComponentInfo> createResolvedComponentsForTestWithOtherProfile(
3070             int numberOfResults, int userId) {
3071         List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
3072         for (int i = 0; i < numberOfResults; i++) {
3073             if (i == 0) {
3074                 infoList.add(
3075                         ResolverDataProvider.createResolvedComponentInfoWithOtherId(i, userId,
3076                                 PERSONAL_USER_HANDLE));
3077             } else {
3078                 infoList.add(ResolverDataProvider.createResolvedComponentInfo(i,
3079                         PERSONAL_USER_HANDLE));
3080             }
3081         }
3082         return infoList;
3083     }
3084 
createResolvedComponentsForTestWithUserId( int numberOfResults, int userId)3085     private List<ResolvedComponentInfo> createResolvedComponentsForTestWithUserId(
3086             int numberOfResults, int userId) {
3087         List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
3088         for (int i = 0; i < numberOfResults; i++) {
3089             infoList.add(ResolverDataProvider.createResolvedComponentInfoWithOtherId(i, userId,
3090                     PERSONAL_USER_HANDLE));
3091         }
3092         return infoList;
3093     }
3094 
createDirectShareTargets(int numberOfResults, String packageName)3095     private List<ChooserTarget> createDirectShareTargets(int numberOfResults, String packageName) {
3096         Icon icon = Icon.createWithBitmap(createBitmap());
3097         String testTitle = "testTitle";
3098         List<ChooserTarget> targets = new ArrayList<>();
3099         for (int i = 0; i < numberOfResults; i++) {
3100             ComponentName componentName;
3101             if (packageName.isEmpty()) {
3102                 componentName = ResolverDataProvider.createComponentName(i);
3103             } else {
3104                 componentName = new ComponentName(packageName, packageName + ".class");
3105             }
3106             ChooserTarget tempTarget = new ChooserTarget(
3107                     testTitle + i,
3108                     icon,
3109                     (float) (1 - ((i + 1) / 10.0)),
3110                     componentName,
3111                     null);
3112             targets.add(tempTarget);
3113         }
3114         return targets;
3115     }
3116 
waitForIdle()3117     private void waitForIdle() {
3118         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
3119     }
3120 
createBitmap()3121     private Bitmap createBitmap() {
3122         int width = 200;
3123         int height = 200;
3124         Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
3125         Canvas canvas = new Canvas(bitmap);
3126 
3127         Paint paint = new Paint();
3128         paint.setColor(Color.RED);
3129         paint.setStyle(Paint.Style.FILL);
3130         canvas.drawPaint(paint);
3131 
3132         paint.setColor(Color.WHITE);
3133         paint.setAntiAlias(true);
3134         paint.setTextSize(14.f);
3135         paint.setTextAlign(Paint.Align.CENTER);
3136         canvas.drawText("Hi!", (width / 2.f), (height / 2.f), paint);
3137 
3138         return bitmap;
3139     }
3140 
createShortcuts(Context context)3141     private List<ShareShortcutInfo> createShortcuts(Context context) {
3142         Intent testIntent = new Intent("TestIntent");
3143 
3144         List<ShareShortcutInfo> shortcuts = new ArrayList<>();
3145         shortcuts.add(new ShareShortcutInfo(
3146                 new ShortcutInfo.Builder(context, "shortcut1")
3147                         .setIntent(testIntent).setShortLabel("label1").setRank(3).build(), // 0  2
3148                 new ComponentName("package1", "class1")));
3149         shortcuts.add(new ShareShortcutInfo(
3150                 new ShortcutInfo.Builder(context, "shortcut2")
3151                         .setIntent(testIntent).setShortLabel("label2").setRank(7).build(), // 1  3
3152                 new ComponentName("package2", "class2")));
3153         shortcuts.add(new ShareShortcutInfo(
3154                 new ShortcutInfo.Builder(context, "shortcut3")
3155                         .setIntent(testIntent).setShortLabel("label3").setRank(1).build(), // 2  0
3156                 new ComponentName("package3", "class3")));
3157         shortcuts.add(new ShareShortcutInfo(
3158                 new ShortcutInfo.Builder(context, "shortcut4")
3159                         .setIntent(testIntent).setShortLabel("label4").setRank(3).build(), // 3  2
3160                 new ComponentName("package4", "class4")));
3161 
3162         return shortcuts;
3163     }
3164 
assertCorrectShortcutToChooserTargetConversion(List<ShareShortcutInfo> shortcuts, List<ChooserTarget> chooserTargets, int[] expectedOrder, float[] expectedScores)3165     private void assertCorrectShortcutToChooserTargetConversion(List<ShareShortcutInfo> shortcuts,
3166             List<ChooserTarget> chooserTargets, int[] expectedOrder, float[] expectedScores) {
3167         assertEquals(expectedOrder.length, chooserTargets.size());
3168         for (int i = 0; i < chooserTargets.size(); i++) {
3169             ChooserTarget ct = chooserTargets.get(i);
3170             ShortcutInfo si = shortcuts.get(expectedOrder[i]).getShortcutInfo();
3171             ComponentName cn = shortcuts.get(expectedOrder[i]).getTargetComponent();
3172 
3173             assertEquals(si.getId(), ct.getIntentExtras().getString(Intent.EXTRA_SHORTCUT_ID));
3174             assertEquals(si.getShortLabel(), ct.getTitle());
3175             assertThat(Math.abs(expectedScores[i] - ct.getScore()) < 0.000001, is(true));
3176             assertEquals(cn.flattenToString(), ct.getComponentName().flattenToString());
3177         }
3178     }
3179 
3180     private void markWorkProfileUserAvailable() {
3181         ChooserActivityOverrideData.getInstance().workProfileUserHandle = UserHandle.of(10);
3182     }
3183 
3184     private void markCloneProfileUserAvailable() {
3185         ChooserActivityOverrideData.getInstance().cloneProfileUserHandle = UserHandle.of(11);
3186     }
3187 
3188     private void setupResolverControllers(
3189             List<ResolvedComponentInfo> personalResolvedComponentInfos,
3190             List<ResolvedComponentInfo> workResolvedComponentInfos) {
3191         when(
3192                 ChooserActivityOverrideData
3193                         .getInstance()
3194                         .resolverListController
3195                         .getResolversForIntent(
3196                                 Mockito.anyBoolean(),
3197                                 Mockito.anyBoolean(),
3198                                 Mockito.anyBoolean(),
3199                                 Mockito.isA(List.class)))
3200                 .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
3201         when(
3202                 ChooserActivityOverrideData
3203                         .getInstance()
3204                         .workResolverListController
3205                         .getResolversForIntent(
3206                                 Mockito.anyBoolean(),
3207                                 Mockito.anyBoolean(),
3208                                 Mockito.anyBoolean(),
3209                                 Mockito.isA(List.class)))
3210                 .thenReturn(new ArrayList<>(workResolvedComponentInfos));
3211         when(
3212                 ChooserActivityOverrideData
3213                         .getInstance()
3214                         .workResolverListController
3215                         .getResolversForIntentAsUser(
3216                                 Mockito.anyBoolean(),
3217                                 Mockito.anyBoolean(),
3218                                 Mockito.anyBoolean(),
3219                                 Mockito.isA(List.class),
3220                                 eq(UserHandle.SYSTEM)))
3221                 .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
3222     }
3223 
3224     private Matcher<View> withIdFromRuntimeResource(String id) {
3225         return withId(getRuntimeResourceId(id, "id"));
3226     }
3227 
3228     private Matcher<View> withTextFromRuntimeResource(String id) {
3229         return withText(getRuntimeResourceId(id, "string"));
3230     }
3231 
3232     private static GridRecyclerSpanCountMatcher withGridColumnCount(int columnCount) {
3233         return new GridRecyclerSpanCountMatcher(Matchers.is(columnCount));
3234     }
3235 
3236     private static class GridRecyclerSpanCountMatcher extends
3237             BoundedDiagnosingMatcher<View, RecyclerView> {
3238 
3239         private final Matcher<Integer> mIntegerMatcher;
3240 
3241         private GridRecyclerSpanCountMatcher(Matcher<Integer> integerMatcher) {
3242             super(RecyclerView.class);
3243             this.mIntegerMatcher = integerMatcher;
3244         }
3245 
3246         @Override
3247         protected void describeMoreTo(Description description) {
3248             description.appendText("RecyclerView grid layout span count to match: ");
3249             this.mIntegerMatcher.describeTo(description);
3250         }
3251 
3252         @Override
3253         protected boolean matchesSafely(RecyclerView view, Description mismatchDescription) {
3254             int spanCount = ((GridLayoutManager) view.getLayoutManager()).getSpanCount();
3255             if (this.mIntegerMatcher.matches(spanCount)) {
3256                 return true;
3257             } else {
3258                 mismatchDescription.appendText("RecyclerView grid layout span count was ")
3259                         .appendValue(spanCount);
3260                 return false;
3261             }
3262         }
3263     }
3264 
3265     private void givenAppTargets(int appCount) {
3266         List<ResolvedComponentInfo> resolvedComponentInfos =
3267                 createResolvedComponentsForTest(appCount);
3268         when(
3269                 ChooserActivityOverrideData
3270                         .getInstance()
3271                         .resolverListController
3272                         .getResolversForIntent(
3273                                 Mockito.anyBoolean(),
3274                                 Mockito.anyBoolean(),
3275                                 Mockito.anyBoolean(),
3276                                 Mockito.isA(List.class)))
3277                 .thenReturn(resolvedComponentInfos);
3278     }
3279 
3280     private void updateMaxTargetsPerRowResource(int targetsPerRow) {
3281         ChooserActivityOverrideData.getInstance().resources = Mockito.spy(
3282                 InstrumentationRegistry.getInstrumentation().getContext().getResources());
3283         when(
3284                 ChooserActivityOverrideData
3285                         .getInstance()
3286                         .resources
3287                         .getInteger(R.integer.config_chooser_max_targets_per_row))
3288                 .thenReturn(targetsPerRow);
3289     }
3290 
3291     // ChooserWrapperActivity inherits from the framework ChooserActivity, so if the framework
3292     // resources have been updated since the framework was last built/pushed, the inherited behavior
3293     // (which is the focus of our testing) will still be implemented in terms of the old resource
3294     // IDs; then when we try to assert those IDs in tests (e.g. `onView(withText(R.string.foo))`),
3295     // the expected values won't match. The tests can instead call this method (with the same
3296     // general semantics as Resources#getIdentifier() e.g. `getRuntimeResourceId("foo", "string")`)
3297     // to refer to the resource by that name in the runtime chooser, regardless of whether the
3298     // framework code on the device is up-to-date.
3299     // TODO: is there a better way to do this? (Other than abandoning inheritance-based DI wrapper?)
3300     private int getRuntimeResourceId(String name, String defType) {
3301         int id = -1;
3302         if (ChooserActivityOverrideData.getInstance().resources != null) {
3303             id = ChooserActivityOverrideData.getInstance().resources.getIdentifier(
3304                   name, defType, "android");
3305         } else {
3306             id = mActivityRule.getActivity().getResources().getIdentifier(name, defType, "android");
3307         }
3308         assertThat(id, greaterThan(0));
3309 
3310         return id;
3311     }
3312 }
3313