• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.intentresolver;
18 
19 import static androidx.test.espresso.Espresso.onView;
20 import static androidx.test.espresso.action.ViewActions.click;
21 import static androidx.test.espresso.action.ViewActions.swipeUp;
22 import static androidx.test.espresso.assertion.ViewAssertions.matches;
23 import static androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
24 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
25 import static androidx.test.espresso.matcher.ViewMatchers.isEnabled;
26 import static androidx.test.espresso.matcher.ViewMatchers.withId;
27 import static androidx.test.espresso.matcher.ViewMatchers.withText;
28 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
29 
30 import static com.android.intentresolver.MatcherUtils.first;
31 import static com.android.intentresolver.ResolverWrapperActivity.sOverrides;
32 
33 import static org.hamcrest.CoreMatchers.allOf;
34 import static org.hamcrest.CoreMatchers.is;
35 import static org.hamcrest.CoreMatchers.not;
36 import static org.hamcrest.MatcherAssert.assertThat;
37 import static org.junit.Assert.assertFalse;
38 import static org.junit.Assert.assertNull;
39 import static org.junit.Assert.fail;
40 import static org.mockito.ArgumentMatchers.eq;
41 import static org.mockito.Mockito.when;
42 
43 import android.content.Intent;
44 import android.content.pm.ResolveInfo;
45 import android.net.Uri;
46 import android.os.RemoteException;
47 import android.os.UserHandle;
48 import android.text.TextUtils;
49 import android.view.View;
50 import android.widget.RelativeLayout;
51 import android.widget.TextView;
52 
53 import androidx.test.espresso.Espresso;
54 import androidx.test.espresso.NoMatchingViewException;
55 import androidx.test.platform.app.InstrumentationRegistry;
56 import androidx.test.rule.ActivityTestRule;
57 import androidx.test.runner.AndroidJUnit4;
58 
59 import com.android.intentresolver.data.repository.FakeUserRepository;
60 import com.android.intentresolver.data.repository.UserRepository;
61 import com.android.intentresolver.data.repository.UserRepositoryModule;
62 import com.android.intentresolver.inject.ApplicationUser;
63 import com.android.intentresolver.inject.ProfileParent;
64 import com.android.intentresolver.shared.model.User;
65 import com.android.intentresolver.widget.ResolverDrawerLayout;
66 
67 import com.google.android.collect.Lists;
68 
69 import dagger.hilt.android.testing.BindValue;
70 import dagger.hilt.android.testing.HiltAndroidRule;
71 import dagger.hilt.android.testing.HiltAndroidTest;
72 import dagger.hilt.android.testing.UninstallModules;
73 
74 import org.junit.Before;
75 import org.junit.Ignore;
76 import org.junit.Rule;
77 import org.junit.Test;
78 import org.junit.runner.RunWith;
79 import org.mockito.Mockito;
80 
81 import java.util.ArrayList;
82 import java.util.List;
83 
84 /**
85  * Resolver activity instrumentation tests
86  */
87 @RunWith(AndroidJUnit4.class)
88 @HiltAndroidTest
89 @UninstallModules(UserRepositoryModule.class)
90 public class ResolverActivityTest {
91 
92     private static final UserHandle PERSONAL_USER_HANDLE =
93             getInstrumentation().getTargetContext().getUser();
94     private static final UserHandle WORK_PROFILE_USER_HANDLE = UserHandle.of(10);
95     private static final UserHandle CLONE_PROFILE_USER_HANDLE = UserHandle.of(11);
96     private static final User WORK_PROFILE_USER =
97             new User(WORK_PROFILE_USER_HANDLE.getIdentifier(), User.Role.WORK);
98 
99     @Rule(order = 0)
100     public HiltAndroidRule mHiltAndroidRule = new HiltAndroidRule(this);
101 
102     @Rule(order = 1)
103     public ActivityTestRule<ResolverWrapperActivity> mActivityRule =
104             new ActivityTestRule<>(ResolverWrapperActivity.class, false, false);
105 
106     @Before
setup()107     public void setup() {
108         // TODO: use the other form of `adoptShellPermissionIdentity()` where we explicitly list the
109         // permissions we require (which we'll read from the manifest at runtime).
110         getInstrumentation()
111                 .getUiAutomation()
112                 .adoptShellPermissionIdentity();
113 
114         sOverrides.reset();
115     }
116 
117     @BindValue
118     @ApplicationUser
119     public final UserHandle mApplicationUser = PERSONAL_USER_HANDLE;
120 
121     @BindValue
122     @ProfileParent
123     public final UserHandle mProfileParent = PERSONAL_USER_HANDLE;
124 
125     /** For setup of test state, a mutable reference of mUserRepository  */
126     private final FakeUserRepository mFakeUserRepo =
127             new FakeUserRepository(List.of(
128                     new User(PERSONAL_USER_HANDLE.getIdentifier(), User.Role.PERSONAL)
129             ));
130 
131     @BindValue
132     public final UserRepository mUserRepository = mFakeUserRepo;
133 
134     @Test
twoOptionsAndUserSelectsOne()135     public void twoOptionsAndUserSelectsOne() throws InterruptedException {
136         Intent sendIntent = createSendImageIntent();
137         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2,
138                 PERSONAL_USER_HANDLE);
139 
140         setupResolverControllers(resolvedComponentInfos);
141 
142         final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
143         Espresso.registerIdlingResources(activity.getLabelIdlingResource());
144         waitForIdle();
145 
146         assertThat(activity.getAdapter().getCount(), is(2));
147 
148         ResolveInfo[] chosen = new ResolveInfo[1];
149         sOverrides.onSafelyStartInternalCallback = result -> {
150             chosen[0] = result.first.getResolveInfo();
151             return true;
152         };
153 
154         ResolveInfo toChoose = resolvedComponentInfos.get(0).getResolveInfoAt(0);
155         onView(withText(toChoose.activityInfo.name))
156                 .perform(click());
157         onView(withId(com.android.internal.R.id.button_once))
158                 .perform(click());
159         waitForIdle();
160         assertThat(chosen[0], is(toChoose));
161     }
162 
163     @Ignore // Failing - b/144929805
164     @Test
setMaxHeight()165     public void setMaxHeight() throws Exception {
166         Intent sendIntent = createSendImageIntent();
167         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2,
168                 PERSONAL_USER_HANDLE);
169 
170         setupResolverControllers(resolvedComponentInfos);
171         waitForIdle();
172 
173         final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
174         final View viewPager = activity.findViewById(com.android.internal.R.id.profile_pager);
175         final int initialResolverHeight = viewPager.getHeight();
176 
177         activity.runOnUiThread(() -> {
178             ResolverDrawerLayout layout = (ResolverDrawerLayout)
179                     activity.findViewById(
180                             com.android.internal.R.id.contentPanel);
181             ((ResolverDrawerLayout.LayoutParams) viewPager.getLayoutParams()).maxHeight
182                     = initialResolverHeight - 1;
183             // Force a relayout
184             layout.invalidate();
185             layout.requestLayout();
186         });
187         waitForIdle();
188         assertThat("Drawer should be capped at maxHeight",
189                 viewPager.getHeight() == (initialResolverHeight - 1));
190 
191         activity.runOnUiThread(() -> {
192             ResolverDrawerLayout layout = (ResolverDrawerLayout)
193                     activity.findViewById(
194                             com.android.internal.R.id.contentPanel);
195             ((ResolverDrawerLayout.LayoutParams) viewPager.getLayoutParams()).maxHeight
196                     = initialResolverHeight + 1;
197             // Force a relayout
198             layout.invalidate();
199             layout.requestLayout();
200         });
201         waitForIdle();
202         assertThat("Drawer should not change height if its height is less than maxHeight",
203                 viewPager.getHeight() == initialResolverHeight);
204     }
205 
206     @Ignore // Failing - b/144929805
207     @Test
setShowAtTopToTrue()208     public void setShowAtTopToTrue() throws Exception {
209         Intent sendIntent = createSendImageIntent();
210         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2,
211                 PERSONAL_USER_HANDLE);
212 
213         setupResolverControllers(resolvedComponentInfos);
214         waitForIdle();
215 
216         final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
217         final View viewPager = activity.findViewById(com.android.internal.R.id.profile_pager);
218         final View divider = activity.findViewById(com.android.internal.R.id.divider);
219         final RelativeLayout profileView =
220                 (RelativeLayout) activity.findViewById(com.android.internal.R.id.profile_button)
221                         .getParent();
222         assertThat("Drawer should show at bottom by default",
223                 profileView.getBottom() + divider.getHeight() == viewPager.getTop()
224                         && profileView.getTop() > 0);
225 
226         activity.runOnUiThread(() -> {
227             ResolverDrawerLayout layout = (ResolverDrawerLayout)
228                     activity.findViewById(
229                             com.android.internal.R.id.contentPanel);
230             layout.setShowAtTop(true);
231         });
232         waitForIdle();
233         assertThat("Drawer should show at top with new attribute",
234                 profileView.getBottom() + divider.getHeight() == viewPager.getTop()
235                         && profileView.getTop() == 0);
236     }
237 
238     @Test
hasLastChosenActivity()239     public void hasLastChosenActivity() throws Exception {
240         Intent sendIntent = createSendImageIntent();
241         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2,
242                 PERSONAL_USER_HANDLE);
243         ResolveInfo toChoose = resolvedComponentInfos.get(0).getResolveInfoAt(0);
244 
245         setupResolverControllers(resolvedComponentInfos);
246         when(sOverrides.resolverListController.getLastChosen())
247                 .thenReturn(resolvedComponentInfos.get(0).getResolveInfoAt(0));
248 
249         final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
250         waitForIdle();
251 
252         // The other entry is filtered to the last used slot
253         assertThat(activity.getAdapter().getCount(), is(1));
254         assertThat(activity.getAdapter().getPlaceholderCount(), is(1));
255 
256         ResolveInfo[] chosen = new ResolveInfo[1];
257         sOverrides.onSafelyStartInternalCallback = result -> {
258             chosen[0] = result.first.getResolveInfo();
259             return true;
260         };
261 
262         onView(withId(com.android.internal.R.id.button_once)).perform(click());
263         waitForIdle();
264         assertThat(chosen[0], is(toChoose));
265     }
266 
267     @Test
hasOtherProfileOneOption()268     public void hasOtherProfileOneOption() throws Exception {
269         List<ResolvedComponentInfo> personalResolvedComponentInfos =
270                 createResolvedComponentsForTestWithOtherProfile(2, /* userId */ 10,
271                         PERSONAL_USER_HANDLE);
272         markOtherProfileAvailability(/* workAvailable= */ true, /* cloneAvailable= */ false);
273         List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4,
274                 WORK_PROFILE_USER_HANDLE);
275         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
276 
277         ResolveInfo toChoose = personalResolvedComponentInfos.get(1).getResolveInfoAt(0);
278         Intent sendIntent = createSendImageIntent();
279         final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
280         Espresso.registerIdlingResources(activity.getLabelIdlingResource());
281         waitForIdle();
282 
283         // The other entry is filtered to the last used slot
284         assertThat(activity.getAdapter().getCount(), is(1));
285 
286         ResolveInfo[] chosen = new ResolveInfo[1];
287         sOverrides.onSafelyStartInternalCallback = result -> {
288             chosen[0] = result.first.getResolveInfo();
289             return true;
290         };
291         // Make a stable copy of the components as the original list may be modified
292         List<ResolvedComponentInfo> stableCopy =
293                 createResolvedComponentsForTestWithOtherProfile(2, /* userId= */ 10,
294                         PERSONAL_USER_HANDLE);
295         // We pick the first one as there is another one in the work profile side
296         onView(first(withText(stableCopy.get(1).getResolveInfoAt(0).activityInfo.name)))
297                 .perform(click());
298         onView(withId(com.android.internal.R.id.button_once))
299                 .perform(click());
300         waitForIdle();
301         assertThat(chosen[0], is(toChoose));
302     }
303 
304     @Test
hasOtherProfileTwoOptionsAndUserSelectsOne()305     public void hasOtherProfileTwoOptionsAndUserSelectsOne() throws Exception {
306         Intent sendIntent = createSendImageIntent();
307         List<ResolvedComponentInfo> resolvedComponentInfos =
308                 createResolvedComponentsForTestWithOtherProfile(3, PERSONAL_USER_HANDLE);
309         ResolveInfo toChoose = resolvedComponentInfos.get(1).getResolveInfoAt(0);
310 
311         setupResolverControllers(resolvedComponentInfos);
312 
313         final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
314         Espresso.registerIdlingResources(activity.getLabelIdlingResource());
315         waitForIdle();
316 
317         // The other entry is filtered to the other profile slot
318         assertThat(activity.getAdapter().getCount(), is(2));
319 
320         ResolveInfo[] chosen = new ResolveInfo[1];
321         sOverrides.onSafelyStartInternalCallback = result -> {
322             chosen[0] = result.first.getResolveInfo();
323             return true;
324         };
325 
326         // Confirm that the button bar is disabled by default
327         onView(withId(com.android.internal.R.id.button_once)).check(matches(not(isEnabled())));
328 
329         // Make a stable copy of the components as the original list may be modified
330         List<ResolvedComponentInfo> stableCopy =
331                 createResolvedComponentsForTestWithOtherProfile(2, PERSONAL_USER_HANDLE);
332 
333         onView(withText(stableCopy.get(1).getResolveInfoAt(0).activityInfo.name))
334                 .perform(click());
335         onView(withId(com.android.internal.R.id.button_once)).perform(click());
336         waitForIdle();
337         assertThat(chosen[0], is(toChoose));
338     }
339 
340 
341     @Test
hasLastChosenActivityAndOtherProfile()342     public void hasLastChosenActivityAndOtherProfile() throws Exception {
343         // In this case we prefer the other profile and don't display anything about the last
344         // chosen activity.
345         Intent sendIntent = createSendImageIntent();
346         List<ResolvedComponentInfo> resolvedComponentInfos =
347                 createResolvedComponentsForTestWithOtherProfile(3, PERSONAL_USER_HANDLE);
348         ResolveInfo toChoose = resolvedComponentInfos.get(1).getResolveInfoAt(0);
349 
350         setupResolverControllers(resolvedComponentInfos);
351         when(sOverrides.resolverListController.getLastChosen())
352                 .thenReturn(resolvedComponentInfos.get(1).getResolveInfoAt(0));
353 
354         final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
355         Espresso.registerIdlingResources(activity.getLabelIdlingResource());
356         waitForIdle();
357 
358         // The other entry is filtered to the other profile slot
359         assertThat(activity.getAdapter().getCount(), is(2));
360 
361         ResolveInfo[] chosen = new ResolveInfo[1];
362         sOverrides.onSafelyStartInternalCallback = result -> {
363             chosen[0] = result.first.getResolveInfo();
364             return true;
365         };
366 
367         // Confirm that the button bar is disabled by default
368         onView(withId(com.android.internal.R.id.button_once)).check(matches(not(isEnabled())));
369 
370         // Make a stable copy of the components as the original list may be modified
371         List<ResolvedComponentInfo> stableCopy =
372                 createResolvedComponentsForTestWithOtherProfile(2, PERSONAL_USER_HANDLE);
373 
374         onView(withText(stableCopy.get(1).getResolveInfoAt(0).activityInfo.name))
375                 .perform(click());
376         onView(withId(com.android.internal.R.id.button_once)).perform(click());
377         waitForIdle();
378         assertThat(chosen[0], is(toChoose));
379     }
380 
381     @Test
testWorkTab_displayedWhenWorkProfileUserAvailable()382     public void testWorkTab_displayedWhenWorkProfileUserAvailable() {
383         Intent sendIntent = createSendImageIntent();
384         markOtherProfileAvailability(/* workAvailable= */ true, /* cloneAvailable= */ false);
385 
386         mActivityRule.launchActivity(sendIntent);
387         waitForIdle();
388 
389         onView(withId(com.android.internal.R.id.tabs)).check(matches(isDisplayed()));
390     }
391 
392     @Test
testWorkTab_hiddenWhenWorkProfileUserNotAvailable()393     public void testWorkTab_hiddenWhenWorkProfileUserNotAvailable() {
394         Intent sendIntent = createSendImageIntent();
395 
396         mActivityRule.launchActivity(sendIntent);
397         waitForIdle();
398 
399         onView(withId(com.android.internal.R.id.tabs)).check(matches(not(isDisplayed())));
400     }
401 
402     @Test
testWorkTab_workTabListPopulatedBeforeGoingToTab()403     public void testWorkTab_workTabListPopulatedBeforeGoingToTab() throws InterruptedException {
404         List<ResolvedComponentInfo> personalResolvedComponentInfos =
405                 createResolvedComponentsForTestWithOtherProfile(3, /* userId = */ 10,
406                         PERSONAL_USER_HANDLE);
407         markOtherProfileAvailability(/* workAvailable= */ true, /* cloneAvailable= */ false);
408         List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4,
409                 WORK_PROFILE_USER_HANDLE);
410         setupResolverControllers(personalResolvedComponentInfos,
411                 new ArrayList<>(workResolvedComponentInfos));
412         Intent sendIntent = createSendImageIntent();
413 
414         final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
415         waitForIdle();
416 
417         assertThat(activity.getCurrentUserHandle().getIdentifier(), is(0));
418         // The work list adapter must be populated in advance before tapping the other tab
419         assertThat(activity.getWorkListAdapter().getCount(), is(4));
420     }
421 
422     @Test
testWorkTab_workTabUsesExpectedAdapter()423     public void testWorkTab_workTabUsesExpectedAdapter() {
424         markOtherProfileAvailability(/* workAvailable= */ true, /* cloneAvailable= */ false);
425         List<ResolvedComponentInfo> personalResolvedComponentInfos =
426                 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10,
427                         PERSONAL_USER_HANDLE);
428         List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4,
429                 WORK_PROFILE_USER_HANDLE);
430         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
431         Intent sendIntent = createSendImageIntent();
432 
433         final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
434         waitForIdle();
435         onView(withText(R.string.resolver_work_tab)).perform(click());
436 
437         assertThat(activity.getCurrentUserHandle().getIdentifier(), is(10));
438         assertThat(activity.getWorkListAdapter().getCount(), is(4));
439     }
440 
441     @Test
testWorkTab_personalTabUsesExpectedAdapter()442     public void testWorkTab_personalTabUsesExpectedAdapter() {
443         markOtherProfileAvailability(/* workAvailable= */ true, /* cloneAvailable= */ false);
444         List<ResolvedComponentInfo> personalResolvedComponentInfos =
445                 createResolvedComponentsForTestWithOtherProfile(3, PERSONAL_USER_HANDLE);
446         List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4,
447                 WORK_PROFILE_USER_HANDLE);
448         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
449         Intent sendIntent = createSendImageIntent();
450 
451         final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
452         waitForIdle();
453         onView(withText(R.string.resolver_work_tab)).perform(click());
454 
455         assertThat(activity.getCurrentUserHandle().getIdentifier(), is(10));
456         assertThat(activity.getPersonalListAdapter().getCount(), is(2));
457     }
458 
459     @Test
testWorkTab_workProfileHasExpectedNumberOfTargets()460     public void testWorkTab_workProfileHasExpectedNumberOfTargets() throws InterruptedException {
461         markOtherProfileAvailability(/* workAvailable= */ true, /* cloneAvailable= */ false);
462         List<ResolvedComponentInfo> personalResolvedComponentInfos =
463                 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10,
464                         PERSONAL_USER_HANDLE);
465         List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4,
466                 WORK_PROFILE_USER_HANDLE);
467         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
468         Intent sendIntent = createSendImageIntent();
469 
470         final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
471         waitForIdle();
472 
473         onView(withText(R.string.resolver_work_tab))
474                 .perform(click());
475         waitForIdle();
476         assertThat(activity.getWorkListAdapter().getCount(), is(4));
477     }
478 
479     @Test
testWorkTab_selectingWorkTabAppOpensAppInWorkProfile()480     public void testWorkTab_selectingWorkTabAppOpensAppInWorkProfile() throws InterruptedException {
481         markOtherProfileAvailability(/* workAvailable= */ true, /* cloneAvailable= */ false);
482         List<ResolvedComponentInfo> personalResolvedComponentInfos =
483                 createResolvedComponentsForTestWithOtherProfile(3,
484                         /* userId */ WORK_PROFILE_USER_HANDLE.getIdentifier(),
485                         PERSONAL_USER_HANDLE);
486         List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4,
487                 WORK_PROFILE_USER_HANDLE);
488         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
489         Intent sendIntent = createSendImageIntent();
490         ResolveInfo[] chosen = new ResolveInfo[1];
491         sOverrides.onSafelyStartInternalCallback = result -> {
492             chosen[0] = result.first.getResolveInfo();
493             return true;
494         };
495 
496         mActivityRule.launchActivity(sendIntent);
497         waitForIdle();
498         onView(withText(R.string.resolver_work_tab))
499                 .perform(click());
500         waitForIdle();
501         onView(first(allOf(withText(workResolvedComponentInfos.get(0)
502                 .getResolveInfoAt(0).activityInfo.applicationInfo.name), isCompletelyDisplayed())))
503                 .perform(click());
504         onView(withId(com.android.internal.R.id.button_once))
505                 .perform(click());
506 
507         waitForIdle();
508         assertThat(chosen[0], is(workResolvedComponentInfos.get(0).getResolveInfoAt(0)));
509     }
510 
511     @Test
testWorkTab_noPersonalApps_workTabHasExpectedNumberOfTargets()512     public void testWorkTab_noPersonalApps_workTabHasExpectedNumberOfTargets()
513             throws InterruptedException {
514         markOtherProfileAvailability(/* workAvailable= */ true, /* cloneAvailable= */ false);
515         List<ResolvedComponentInfo> personalResolvedComponentInfos =
516                 createResolvedComponentsForTestWithOtherProfile(1, PERSONAL_USER_HANDLE);
517         List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4,
518                 WORK_PROFILE_USER_HANDLE);
519         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
520         Intent sendIntent = createSendImageIntent();
521 
522         final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
523         waitForIdle();
524         onView(withText(R.string.resolver_work_tab))
525                 .perform(click());
526 
527         waitForIdle();
528         assertThat(activity.getWorkListAdapter().getCount(), is(4));
529     }
530 
531     @Test
testWorkTab_headerIsVisibleInPersonalTab()532     public void testWorkTab_headerIsVisibleInPersonalTab() {
533         markOtherProfileAvailability(/* workAvailable= */ true, /* cloneAvailable= */ false);
534         List<ResolvedComponentInfo> personalResolvedComponentInfos =
535                 createResolvedComponentsForTestWithOtherProfile(1, PERSONAL_USER_HANDLE);
536         List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4,
537                 WORK_PROFILE_USER_HANDLE);
538         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
539         Intent sendIntent = createOpenWebsiteIntent();
540 
541         final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
542         waitForIdle();
543         TextView headerText = activity.findViewById(com.android.internal.R.id.title);
544         String initialText = headerText.getText().toString();
545         assertFalse("Header text is empty.", initialText.isEmpty());
546         assertThat(headerText.getVisibility(), is(View.VISIBLE));
547     }
548 
549     @Test
testWorkTab_switchTabs_headerStaysSame()550     public void testWorkTab_switchTabs_headerStaysSame() {
551         markOtherProfileAvailability(/* workAvailable= */ true, /* cloneAvailable= */ false);
552         List<ResolvedComponentInfo> personalResolvedComponentInfos =
553                 createResolvedComponentsForTestWithOtherProfile(1, PERSONAL_USER_HANDLE);
554         List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4,
555                 WORK_PROFILE_USER_HANDLE);
556         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
557         Intent sendIntent = createOpenWebsiteIntent();
558 
559         final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
560         waitForIdle();
561         TextView headerText = activity.findViewById(com.android.internal.R.id.title);
562         String initialText = headerText.getText().toString();
563         onView(withText(R.string.resolver_work_tab))
564                 .perform(click());
565 
566         waitForIdle();
567         String currentText = headerText.getText().toString();
568         assertThat(headerText.getVisibility(), is(View.VISIBLE));
569         assertThat(String.format("Header text is not the same when switching tabs, personal profile"
570                         + " header was %s but work profile header is %s", initialText, currentText),
571                 TextUtils.equals(initialText, currentText));
572     }
573 
574     @Test
testWorkTab_noPersonalApps_canStartWorkApps()575     public void testWorkTab_noPersonalApps_canStartWorkApps()
576             throws InterruptedException {
577         markOtherProfileAvailability(/* workAvailable= */ true, /* cloneAvailable= */ false);
578         List<ResolvedComponentInfo> personalResolvedComponentInfos =
579                 createResolvedComponentsForTestWithOtherProfile(3, /* userId= */ 10,
580                         PERSONAL_USER_HANDLE);
581         List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4,
582                 WORK_PROFILE_USER_HANDLE);
583         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
584         Intent sendIntent = createSendImageIntent();
585         ResolveInfo[] chosen = new ResolveInfo[1];
586         sOverrides.onSafelyStartInternalCallback = result -> {
587             chosen[0] = result.first.getResolveInfo();
588             return true;
589         };
590 
591         mActivityRule.launchActivity(sendIntent);
592         waitForIdle();
593         onView(withText(R.string.resolver_work_tab))
594                 .perform(click());
595         waitForIdle();
596         onView(first(allOf(
597                 withText(workResolvedComponentInfos.get(0)
598                         .getResolveInfoAt(0).activityInfo.applicationInfo.name),
599                 isDisplayed())))
600                 .perform(click());
601         onView(withId(com.android.internal.R.id.button_once))
602                 .perform(click());
603         waitForIdle();
604 
605         assertThat(chosen[0], is(workResolvedComponentInfos.get(0).getResolveInfoAt(0)));
606     }
607 
608     @Test
testWorkTab_crossProfileIntentsDisabled_personalToWork_emptyStateShown()609     public void testWorkTab_crossProfileIntentsDisabled_personalToWork_emptyStateShown() {
610         markOtherProfileAvailability(/* workAvailable= */ true, /* cloneAvailable= */ false);
611         int workProfileTargets = 4;
612         List<ResolvedComponentInfo> personalResolvedComponentInfos =
613                 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10,
614                         PERSONAL_USER_HANDLE);
615         List<ResolvedComponentInfo> workResolvedComponentInfos =
616                 createResolvedComponentsForTest(workProfileTargets, WORK_PROFILE_USER_HANDLE);
617         sOverrides.hasCrossProfileIntents = false;
618         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
619         Intent sendIntent = createSendImageIntent();
620         sendIntent.setType("TestType");
621 
622         mActivityRule.launchActivity(sendIntent);
623         waitForIdle();
624         onView(withText(R.string.resolver_work_tab)).perform(click());
625         waitForIdle();
626         onView(withId(com.android.internal.R.id.contentPanel))
627                 .perform(swipeUp());
628 
629         onView(withText(R.string.resolver_cross_profile_blocked))
630                 .check(matches(isDisplayed()));
631     }
632 
633     @Test
testWorkTab_workProfileDisabled_emptyStateShown()634     public void testWorkTab_workProfileDisabled_emptyStateShown() {
635         markOtherProfileAvailability(/* workAvailable= */ true, /* cloneAvailable= */ false);
636         int workProfileTargets = 4;
637         List<ResolvedComponentInfo> personalResolvedComponentInfos =
638                 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10,
639                         PERSONAL_USER_HANDLE);
640         List<ResolvedComponentInfo> workResolvedComponentInfos =
641                 createResolvedComponentsForTest(workProfileTargets, WORK_PROFILE_USER_HANDLE);
642         mFakeUserRepo.updateState(WORK_PROFILE_USER, false);
643         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
644         Intent sendIntent = createSendImageIntent();
645         sendIntent.setType("TestType");
646 
647         mActivityRule.launchActivity(sendIntent);
648         waitForIdle();
649         onView(withId(com.android.internal.R.id.contentPanel))
650                 .perform(swipeUp());
651         onView(withText(R.string.resolver_work_tab)).perform(click());
652         waitForIdle();
653 
654         onView(withText(R.string.resolver_turn_on_work_apps))
655                 .check(matches(isDisplayed()));
656     }
657 
658     @Test
testWorkTab_noWorkAppsAvailable_emptyStateShown()659     public void testWorkTab_noWorkAppsAvailable_emptyStateShown() {
660         markOtherProfileAvailability(/* workAvailable= */ true, /* cloneAvailable= */ false);
661         List<ResolvedComponentInfo> personalResolvedComponentInfos =
662                 createResolvedComponentsForTest(3, PERSONAL_USER_HANDLE);
663         List<ResolvedComponentInfo> workResolvedComponentInfos =
664                 createResolvedComponentsForTest(0, WORK_PROFILE_USER_HANDLE);
665         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
666         Intent sendIntent = createSendImageIntent();
667         sendIntent.setType("TestType");
668 
669         mActivityRule.launchActivity(sendIntent);
670         waitForIdle();
671         onView(withId(com.android.internal.R.id.contentPanel))
672                 .perform(swipeUp());
673         onView(withText(R.string.resolver_work_tab)).perform(click());
674         waitForIdle();
675 
676         onView(withText(R.string.resolver_no_work_apps_available))
677                 .check(matches(isDisplayed()));
678     }
679 
680     @Test
testWorkTab_xProfileOff_noAppsAvailable_workOff_xProfileOffEmptyStateShown()681     public void testWorkTab_xProfileOff_noAppsAvailable_workOff_xProfileOffEmptyStateShown() {
682         markOtherProfileAvailability(/* workAvailable= */ true, /* cloneAvailable= */ false);
683         List<ResolvedComponentInfo> personalResolvedComponentInfos =
684                 createResolvedComponentsForTest(3, PERSONAL_USER_HANDLE);
685         List<ResolvedComponentInfo> workResolvedComponentInfos =
686                 createResolvedComponentsForTest(0, WORK_PROFILE_USER_HANDLE);
687         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
688         Intent sendIntent = createSendImageIntent();
689         sendIntent.setType("TestType");
690         mFakeUserRepo.updateState(WORK_PROFILE_USER, false);
691         sOverrides.hasCrossProfileIntents = false;
692 
693         mActivityRule.launchActivity(sendIntent);
694         waitForIdle();
695         onView(withId(com.android.internal.R.id.contentPanel))
696                 .perform(swipeUp());
697         onView(withText(R.string.resolver_work_tab)).perform(click());
698         waitForIdle();
699 
700         onView(withText(R.string.resolver_cross_profile_blocked))
701                 .check(matches(isDisplayed()));
702     }
703 
704     @Test
testMiniResolver()705     public void testMiniResolver() {
706         markOtherProfileAvailability(/* workAvailable= */ true, /* cloneAvailable= */ false);
707         List<ResolvedComponentInfo> personalResolvedComponentInfos =
708                 createResolvedComponentsForTest(1, PERSONAL_USER_HANDLE);
709         List<ResolvedComponentInfo> workResolvedComponentInfos =
710                 createResolvedComponentsForTest(1, WORK_PROFILE_USER_HANDLE);
711         // Personal profile only has a browser
712         personalResolvedComponentInfos.get(0).getResolveInfoAt(0).handleAllWebDataURI = true;
713         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
714         Intent sendIntent = createSendImageIntent();
715         sendIntent.setType("TestType");
716 
717         mActivityRule.launchActivity(sendIntent);
718         waitForIdle();
719         onView(withId(com.android.internal.R.id.open_cross_profile)).check(matches(isDisplayed()));
720     }
721 
722     @Test
testMiniResolver_noCurrentProfileTarget()723     public void testMiniResolver_noCurrentProfileTarget() {
724         markOtherProfileAvailability(/* workAvailable= */ true, /* cloneAvailable= */ false);
725         List<ResolvedComponentInfo> personalResolvedComponentInfos =
726                 createResolvedComponentsForTest(0, PERSONAL_USER_HANDLE);
727         List<ResolvedComponentInfo> workResolvedComponentInfos =
728                 createResolvedComponentsForTest(1, WORK_PROFILE_USER_HANDLE);
729         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
730         Intent sendIntent = createSendImageIntent();
731         sendIntent.setType("TestType");
732 
733         mActivityRule.launchActivity(sendIntent);
734         waitForIdle();
735 
736         // Need to ensure mini resolver doesn't trigger here.
737         assertNotMiniResolver();
738     }
739 
assertNotMiniResolver()740     private void assertNotMiniResolver() {
741         try {
742             onView(withId(com.android.internal.R.id.open_cross_profile))
743                     .check(matches(isDisplayed()));
744         } catch (NoMatchingViewException e) {
745             return;
746         }
747         fail("Mini resolver present but shouldn't be");
748     }
749 
750     @Test
testWorkTab_noAppsAvailable_workOff_noAppsAvailableEmptyStateShown()751     public void testWorkTab_noAppsAvailable_workOff_noAppsAvailableEmptyStateShown() {
752         markOtherProfileAvailability(/* workAvailable= */ true, /* cloneAvailable= */ false);
753         List<ResolvedComponentInfo> personalResolvedComponentInfos =
754                 createResolvedComponentsForTest(3, PERSONAL_USER_HANDLE);
755         List<ResolvedComponentInfo> workResolvedComponentInfos =
756                 createResolvedComponentsForTest(0, WORK_PROFILE_USER_HANDLE);
757         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
758         Intent sendIntent = createSendImageIntent();
759         sendIntent.setType("TestType");
760         mFakeUserRepo.updateState(WORK_PROFILE_USER, false);
761 
762         mActivityRule.launchActivity(sendIntent);
763         waitForIdle();
764         onView(withId(com.android.internal.R.id.contentPanel))
765                 .perform(swipeUp());
766         onView(withText(R.string.resolver_work_tab)).perform(click());
767         waitForIdle();
768 
769         onView(withText(R.string.resolver_no_work_apps_available))
770                 .check(matches(isDisplayed()));
771     }
772 
773     @Test
testWorkTab_onePersonalTarget_emptyStateOnWorkTarget_doesNotAutoLaunch()774     public void testWorkTab_onePersonalTarget_emptyStateOnWorkTarget_doesNotAutoLaunch() {
775         markOtherProfileAvailability(/* workAvailable= */ true, /* cloneAvailable= */ false);
776         int workProfileTargets = 4;
777         List<ResolvedComponentInfo> personalResolvedComponentInfos =
778                 createResolvedComponentsForTestWithOtherProfile(2, /* userId */ 10,
779                         PERSONAL_USER_HANDLE);
780         List<ResolvedComponentInfo> workResolvedComponentInfos =
781                 createResolvedComponentsForTest(workProfileTargets, WORK_PROFILE_USER_HANDLE);
782         sOverrides.hasCrossProfileIntents = false;
783         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
784         Intent sendIntent = createSendImageIntent();
785         sendIntent.setType("TestType");
786         ResolveInfo[] chosen = new ResolveInfo[1];
787         sOverrides.onSafelyStartInternalCallback = result -> {
788             chosen[0] = result.first.getResolveInfo();
789             return true;
790         };
791 
792         mActivityRule.launchActivity(sendIntent);
793         waitForIdle();
794 
795         assertNull(chosen[0]);
796     }
797 
798     @Test
testLayoutWithDefault_withWorkTab_neverShown()799     public void testLayoutWithDefault_withWorkTab_neverShown() throws RemoteException {
800         markOtherProfileAvailability(/* workAvailable= */ true, /* cloneAvailable= */ false);
801 
802         // In this case we prefer the other profile and don't display anything about the last
803         // chosen activity.
804         Intent sendIntent = createSendImageIntent();
805         List<ResolvedComponentInfo> resolvedComponentInfos =
806                 createResolvedComponentsForTest(2, PERSONAL_USER_HANDLE);
807 
808         setupResolverControllers(resolvedComponentInfos);
809         when(sOverrides.resolverListController.getLastChosen())
810                 .thenReturn(resolvedComponentInfos.get(1).getResolveInfoAt(0));
811 
812         final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
813         Espresso.registerIdlingResources(activity.getLabelIdlingResource());
814         waitForIdle();
815 
816         // The other entry is filtered to the last used slot
817         assertThat(activity.getAdapter().hasFilteredItem(), is(false));
818         assertThat(activity.getAdapter().getCount(), is(2));
819         assertThat(activity.getAdapter().getPlaceholderCount(), is(2));
820     }
821 
822     @Test
testClonedProfilePresent_personalAdapterIsSetWithPersonalProfile()823     public void testClonedProfilePresent_personalAdapterIsSetWithPersonalProfile() {
824         // enable cloneProfile
825         markOtherProfileAvailability(/* workAvailable= */ false, /* cloneAvailable= */ true);
826         List<ResolvedComponentInfo> resolvedComponentInfos =
827                 createResolvedComponentsWithCloneProfileForTest(
828                         3,
829                         PERSONAL_USER_HANDLE,
830                         CLONE_PROFILE_USER_HANDLE);
831         setupResolverControllers(resolvedComponentInfos);
832         Intent sendIntent = createSendImageIntent();
833 
834         final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
835         waitForIdle();
836 
837         assertThat(activity.getCurrentUserHandle(), is(PERSONAL_USER_HANDLE));
838         assertThat(activity.getAdapter().getCount(), is(3));
839     }
840 
841     @Test
testClonedProfilePresent_personalTabUsesExpectedAdapter()842     public void testClonedProfilePresent_personalTabUsesExpectedAdapter() {
843         // enable cloneProfile
844         markOtherProfileAvailability(/* workAvailable= */ true, /* cloneAvailable= */ true);
845         List<ResolvedComponentInfo> personalResolvedComponentInfos =
846                 createResolvedComponentsWithCloneProfileForTest(
847                         3,
848                         PERSONAL_USER_HANDLE,
849                         CLONE_PROFILE_USER_HANDLE);
850         List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4,
851                 WORK_PROFILE_USER_HANDLE);
852         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
853         Intent sendIntent = createSendImageIntent();
854 
855         final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
856         waitForIdle();
857 
858         assertThat(activity.getCurrentUserHandle(), is(PERSONAL_USER_HANDLE));
859         assertThat(activity.getAdapter().getCount(), is(3));
860     }
861 
862     @Test
testClonedProfilePresent_layoutWithDefault_neverShown()863     public void testClonedProfilePresent_layoutWithDefault_neverShown() throws Exception {
864         // enable cloneProfile
865         markOtherProfileAvailability(/* workAvailable= */ false, /* cloneAvailable= */ true);
866         Intent sendIntent = createSendImageIntent();
867         List<ResolvedComponentInfo> resolvedComponentInfos =
868                 createResolvedComponentsWithCloneProfileForTest(
869                         2,
870                         PERSONAL_USER_HANDLE,
871                         CLONE_PROFILE_USER_HANDLE);
872 
873         setupResolverControllers(resolvedComponentInfos);
874         when(sOverrides.resolverListController.getLastChosen())
875                 .thenReturn(resolvedComponentInfos.get(0).getResolveInfoAt(0));
876 
877         final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
878         Espresso.registerIdlingResources(activity.getLabelIdlingResource());
879         waitForIdle();
880 
881         assertThat(activity.getAdapter().hasFilteredItem(), is(false));
882         assertThat(activity.getAdapter().getCount(), is(2));
883         assertThat(activity.getAdapter().getPlaceholderCount(), is(2));
884     }
885 
886     @Test
testClonedProfilePresent_alwaysButtonDisabled()887     public void testClonedProfilePresent_alwaysButtonDisabled() throws Exception {
888         // enable cloneProfile
889         markOtherProfileAvailability(/* workAvailable= */ false, /* cloneAvailable= */ true);
890         Intent sendIntent = createSendImageIntent();
891         List<ResolvedComponentInfo> resolvedComponentInfos =
892                 createResolvedComponentsWithCloneProfileForTest(
893                         3,
894                         PERSONAL_USER_HANDLE,
895                         CLONE_PROFILE_USER_HANDLE);
896 
897         setupResolverControllers(resolvedComponentInfos);
898         when(sOverrides.resolverListController.getLastChosen())
899                 .thenReturn(resolvedComponentInfos.get(0).getResolveInfoAt(0));
900 
901         final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
902         waitForIdle();
903 
904         // Confirm that the button bar is disabled by default
905         onView(withId(com.android.internal.R.id.button_once)).check(matches(not(isEnabled())));
906         onView(withId(com.android.internal.R.id.button_always)).check(matches(not(isEnabled())));
907 
908         // Make a stable copy of the components as the original list may be modified
909         List<ResolvedComponentInfo> stableCopy =
910                 createResolvedComponentsForTestWithOtherProfile(2, PERSONAL_USER_HANDLE);
911 
912         onView(withText(stableCopy.get(1).getResolveInfoAt(0).activityInfo.name))
913                 .perform(click());
914 
915         onView(withId(com.android.internal.R.id.button_once)).check(matches(isEnabled()));
916         onView(withId(com.android.internal.R.id.button_always)).check(matches(not(isEnabled())));
917     }
918 
919     @Test
testClonedProfilePresent_personalProfileActivityIsStartedInCorrectUser()920     public void testClonedProfilePresent_personalProfileActivityIsStartedInCorrectUser()
921             throws Exception {
922         // enable cloneProfile
923         markOtherProfileAvailability(/* workAvailable= */ true, /* cloneAvailable= */ true);
924 
925         List<ResolvedComponentInfo> personalResolvedComponentInfos =
926                 createResolvedComponentsWithCloneProfileForTest(
927                         3,
928                         PERSONAL_USER_HANDLE,
929                         CLONE_PROFILE_USER_HANDLE);
930         List<ResolvedComponentInfo> workResolvedComponentInfos =
931                 createResolvedComponentsForTest(3, WORK_PROFILE_USER_HANDLE);
932         sOverrides.hasCrossProfileIntents = false;
933         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
934         Intent sendIntent = createSendImageIntent();
935         sendIntent.setType("TestType");
936         final UserHandle[] selectedActivityUserHandle = new UserHandle[1];
937         sOverrides.onSafelyStartInternalCallback = result -> {
938             selectedActivityUserHandle[0] = result.second;
939             return true;
940         };
941 
942         final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
943         waitForIdle();
944         onView(first(allOf(withText(personalResolvedComponentInfos.get(0)
945                 .getResolveInfoAt(0).activityInfo.applicationInfo.name), isCompletelyDisplayed())))
946                 .perform(click());
947         onView(withId(com.android.internal.R.id.button_once))
948                 .perform(click());
949         waitForIdle();
950 
951         assertThat(selectedActivityUserHandle[0], is(activity.getAdapter().getUserHandle()));
952     }
953 
954     @Test
testClonedProfilePresent_workProfileActivityIsStartedInCorrectUser()955     public void testClonedProfilePresent_workProfileActivityIsStartedInCorrectUser()
956             throws Exception {
957         // enable cloneProfile
958         markOtherProfileAvailability(/* workAvailable= */ true, /* cloneAvailable= */ true);
959 
960         List<ResolvedComponentInfo> personalResolvedComponentInfos =
961                 createResolvedComponentsWithCloneProfileForTest(
962                         3,
963                         PERSONAL_USER_HANDLE,
964                         CLONE_PROFILE_USER_HANDLE);
965         List<ResolvedComponentInfo> workResolvedComponentInfos =
966                 createResolvedComponentsForTest(3, WORK_PROFILE_USER_HANDLE);
967         setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
968         Intent sendIntent = createSendImageIntent();
969         sendIntent.setType("TestType");
970         final UserHandle[] selectedActivityUserHandle = new UserHandle[1];
971         sOverrides.onSafelyStartInternalCallback = result -> {
972             selectedActivityUserHandle[0] = result.second;
973             return true;
974         };
975 
976         final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
977         waitForIdle();
978         onView(withText(R.string.resolver_work_tab))
979                 .perform(click());
980         waitForIdle();
981         onView(first(allOf(withText(workResolvedComponentInfos.get(0)
982                 .getResolveInfoAt(0).activityInfo.applicationInfo.name), isCompletelyDisplayed())))
983                 .perform(click());
984         onView(withId(com.android.internal.R.id.button_once))
985                 .perform(click());
986         waitForIdle();
987 
988         assertThat(selectedActivityUserHandle[0], is(activity.getAdapter().getUserHandle()));
989     }
990 
991     @Test
testClonedProfilePresent_personalProfileResolverComparatorHasCorrectUsers()992     public void testClonedProfilePresent_personalProfileResolverComparatorHasCorrectUsers()
993             throws Exception {
994         // enable cloneProfile
995         markOtherProfileAvailability(/* workAvailable= */ false, /* cloneAvailable= */ true);
996         List<ResolvedComponentInfo> resolvedComponentInfos =
997                 createResolvedComponentsWithCloneProfileForTest(
998                         3,
999                         PERSONAL_USER_HANDLE,
1000                         CLONE_PROFILE_USER_HANDLE);
1001         setupResolverControllers(resolvedComponentInfos);
1002         Intent sendIntent = createSendImageIntent();
1003 
1004         final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
1005         waitForIdle();
1006         List<UserHandle> result = activity
1007                 .getResolverRankerServiceUserHandleList(PERSONAL_USER_HANDLE);
1008 
1009         assertThat(result.containsAll(
1010                 Lists.newArrayList(PERSONAL_USER_HANDLE, CLONE_PROFILE_USER_HANDLE)), is(true));
1011     }
1012 
createSendImageIntent()1013     private Intent createSendImageIntent() {
1014         Intent sendIntent = new Intent();
1015         sendIntent.setAction(Intent.ACTION_SEND);
1016         sendIntent.putExtra(Intent.EXTRA_TEXT, "testing intent sending");
1017         sendIntent.setType("image/jpeg");
1018         return sendIntent;
1019     }
1020 
createOpenWebsiteIntent()1021     private Intent createOpenWebsiteIntent() {
1022         Intent sendIntent = new Intent();
1023         sendIntent.setAction(Intent.ACTION_VIEW);
1024         sendIntent.setData(Uri.parse("https://google.com"));
1025         return sendIntent;
1026     }
1027 
createResolvedComponentsForTest(int numberOfResults, UserHandle resolvedForUser)1028     private List<ResolvedComponentInfo> createResolvedComponentsForTest(int numberOfResults,
1029             UserHandle resolvedForUser) {
1030         List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
1031         for (int i = 0; i < numberOfResults; i++) {
1032             infoList.add(ResolverDataProvider.createResolvedComponentInfo(i, resolvedForUser));
1033         }
1034         return infoList;
1035     }
1036 
createResolvedComponentsWithCloneProfileForTest( int numberOfResults, UserHandle resolvedForPersonalUser, UserHandle resolvedForClonedUser)1037     private List<ResolvedComponentInfo> createResolvedComponentsWithCloneProfileForTest(
1038             int numberOfResults,
1039             UserHandle resolvedForPersonalUser,
1040             UserHandle resolvedForClonedUser) {
1041         List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
1042         for (int i = 0; i < 1; i++) {
1043             infoList.add(ResolverDataProvider.createResolvedComponentInfo(i,
1044                     resolvedForPersonalUser));
1045         }
1046         for (int i = 1; i < numberOfResults; i++) {
1047             infoList.add(ResolverDataProvider.createResolvedComponentInfo(i,
1048                     resolvedForClonedUser));
1049         }
1050         return infoList;
1051     }
1052 
createResolvedComponentsForTestWithOtherProfile( int numberOfResults, UserHandle resolvedForUser)1053     private List<ResolvedComponentInfo> createResolvedComponentsForTestWithOtherProfile(
1054             int numberOfResults,
1055             UserHandle resolvedForUser) {
1056         List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
1057         for (int i = 0; i < numberOfResults; i++) {
1058             if (i == 0) {
1059                 infoList.add(ResolverDataProvider.createResolvedComponentInfoWithOtherId(i,
1060                         resolvedForUser));
1061             } else {
1062                 infoList.add(ResolverDataProvider.createResolvedComponentInfo(i, resolvedForUser));
1063             }
1064         }
1065         return infoList;
1066     }
1067 
createResolvedComponentsForTestWithOtherProfile( int numberOfResults, int userId, UserHandle resolvedForUser)1068     private List<ResolvedComponentInfo> createResolvedComponentsForTestWithOtherProfile(
1069             int numberOfResults, int userId, UserHandle resolvedForUser) {
1070         List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
1071         for (int i = 0; i < numberOfResults; i++) {
1072             if (i == 0) {
1073                 infoList.add(
1074                         ResolverDataProvider.createResolvedComponentInfoWithOtherId(i, userId,
1075                                 resolvedForUser));
1076             } else {
1077                 infoList.add(ResolverDataProvider.createResolvedComponentInfo(i, resolvedForUser));
1078             }
1079         }
1080         return infoList;
1081     }
1082 
waitForIdle()1083     private void waitForIdle() {
1084         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
1085     }
1086 
markOtherProfileAvailability(boolean workAvailable, boolean cloneAvailable)1087     private void markOtherProfileAvailability(boolean workAvailable, boolean cloneAvailable) {
1088         if (workAvailable) {
1089             mFakeUserRepo.addUser(
1090                     new User(WORK_PROFILE_USER_HANDLE.getIdentifier(), User.Role.WORK), true);
1091         }
1092         if (cloneAvailable) {
1093             mFakeUserRepo.addUser(
1094                     new User(CLONE_PROFILE_USER_HANDLE.getIdentifier(), User.Role.CLONE), true);
1095         }
1096     }
1097 
setupResolverControllers( List<ResolvedComponentInfo> personalResolvedComponentInfos)1098     private void setupResolverControllers(
1099             List<ResolvedComponentInfo> personalResolvedComponentInfos) {
1100         setupResolverControllers(personalResolvedComponentInfos, new ArrayList<>());
1101     }
1102 
setupResolverControllers( List<ResolvedComponentInfo> personalResolvedComponentInfos, List<ResolvedComponentInfo> workResolvedComponentInfos)1103     private void setupResolverControllers(
1104             List<ResolvedComponentInfo> personalResolvedComponentInfos,
1105             List<ResolvedComponentInfo> workResolvedComponentInfos) {
1106         when(sOverrides.resolverListController.getResolversForIntentAsUser(
1107                 Mockito.anyBoolean(),
1108                 Mockito.anyBoolean(),
1109                 Mockito.anyBoolean(),
1110                 Mockito.isA(List.class),
1111                 eq(PERSONAL_USER_HANDLE)))
1112                         .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
1113         when(sOverrides.workResolverListController.getResolversForIntentAsUser(
1114                 Mockito.anyBoolean(),
1115                 Mockito.anyBoolean(),
1116                 Mockito.anyBoolean(),
1117                 Mockito.isA(List.class),
1118                 eq(WORK_PROFILE_USER_HANDLE)))
1119                         .thenReturn(new ArrayList<>(workResolvedComponentInfos));
1120     }
1121 }
1122