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