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