blob: f1febed2941be52e1d79ebc418ffb919bbc7e908 [file] [log] [blame]
Nick Chameyev0919a832022-10-10 12:39:19 +00001/*
2 * Copyright (C) 2022 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
17package com.android.intentresolver;
18
Nick Chameyev76e02782022-12-21 15:58:32 +000019import static android.testing.PollingCheck.waitFor;
20
Nick Chameyev0919a832022-10-10 12:39:19 +000021import static androidx.test.espresso.Espresso.onView;
22import static androidx.test.espresso.action.ViewActions.click;
23import static androidx.test.espresso.action.ViewActions.swipeUp;
24import static androidx.test.espresso.assertion.ViewAssertions.matches;
25import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
Nick Chameyev76e02782022-12-21 15:58:32 +000026import static androidx.test.espresso.matcher.ViewMatchers.isSelected;
Nick Chameyev0919a832022-10-10 12:39:19 +000027import static androidx.test.espresso.matcher.ViewMatchers.withId;
28import static androidx.test.espresso.matcher.ViewMatchers.withText;
29
Andrey Epinf9a8f402022-11-28 11:54:33 -080030import static com.android.intentresolver.ChooserWrapperActivity.sOverrides;
Nick Chameyev0919a832022-10-10 12:39:19 +000031import static com.android.intentresolver.UnbundledChooserActivityWorkProfileTest.TestCase.ExpectedBlocker.NO_BLOCKER;
32import static com.android.intentresolver.UnbundledChooserActivityWorkProfileTest.TestCase.ExpectedBlocker.PERSONAL_PROFILE_ACCESS_BLOCKER;
33import static com.android.intentresolver.UnbundledChooserActivityWorkProfileTest.TestCase.ExpectedBlocker.PERSONAL_PROFILE_SHARE_BLOCKER;
34import static com.android.intentresolver.UnbundledChooserActivityWorkProfileTest.TestCase.ExpectedBlocker.WORK_PROFILE_ACCESS_BLOCKER;
35import static com.android.intentresolver.UnbundledChooserActivityWorkProfileTest.TestCase.ExpectedBlocker.WORK_PROFILE_SHARE_BLOCKER;
36import static com.android.intentresolver.UnbundledChooserActivityWorkProfileTest.TestCase.Tab.PERSONAL;
37import static com.android.intentresolver.UnbundledChooserActivityWorkProfileTest.TestCase.Tab.WORK;
Nick Chameyev0919a832022-10-10 12:39:19 +000038
39import static org.hamcrest.CoreMatchers.not;
40import static org.mockito.ArgumentMatchers.eq;
41import static org.mockito.Mockito.when;
42
43import android.companion.DeviceFilter;
44import android.content.Intent;
45import android.os.UserHandle;
46
47import androidx.test.InstrumentationRegistry;
48import androidx.test.espresso.NoMatchingViewException;
49import androidx.test.rule.ActivityTestRule;
50
Nick Chameyev0919a832022-10-10 12:39:19 +000051import com.android.intentresolver.ResolverActivity.ResolvedComponentInfo;
52import com.android.intentresolver.UnbundledChooserActivityWorkProfileTest.TestCase.Tab;
Andrey Epinf9a8f402022-11-28 11:54:33 -080053import com.android.internal.R;
Nick Chameyev0919a832022-10-10 12:39:19 +000054
Nick Chameyev76e02782022-12-21 15:58:32 +000055import junit.framework.AssertionFailedError;
56
Nick Chameyev0919a832022-10-10 12:39:19 +000057import org.junit.Before;
58import org.junit.Rule;
59import org.junit.Test;
60import org.junit.runner.RunWith;
61import org.junit.runners.Parameterized;
62import org.mockito.Mockito;
63
64import java.util.ArrayList;
65import java.util.Arrays;
66import java.util.Collection;
67import java.util.List;
68
69@DeviceFilter.MediumType
70@RunWith(Parameterized.class)
71public class UnbundledChooserActivityWorkProfileTest {
72
73 private static final UserHandle PERSONAL_USER_HANDLE = InstrumentationRegistry
74 .getInstrumentation().getTargetContext().getUser();
75 private static final UserHandle WORK_USER_HANDLE = UserHandle.of(10);
76
77 @Rule
78 public ActivityTestRule<ChooserWrapperActivity> mActivityRule =
79 new ActivityTestRule<>(ChooserWrapperActivity.class, false,
80 false);
81 private final TestCase mTestCase;
82
83 public UnbundledChooserActivityWorkProfileTest(TestCase testCase) {
84 mTestCase = testCase;
85 }
86
87 @Before
88 public void cleanOverrideData() {
89 // TODO: use the other form of `adoptShellPermissionIdentity()` where we explicitly list the
90 // permissions we require (which we'll read from the manifest at runtime).
91 InstrumentationRegistry
92 .getInstrumentation()
93 .getUiAutomation()
94 .adoptShellPermissionIdentity();
95
96 sOverrides.reset();
97 }
98
99 @Test
100 public void testBlocker() {
101 setUpPersonalAndWorkComponentInfos();
102 sOverrides.hasCrossProfileIntents = mTestCase.hasCrossProfileIntents();
103 sOverrides.myUserId = mTestCase.getMyUserHandle().getIdentifier();
104
105 launchActivity(mTestCase.getIsSendAction());
106 switchToTab(mTestCase.getTab());
107
108 switch (mTestCase.getExpectedBlocker()) {
109 case NO_BLOCKER:
110 assertNoBlockerDisplayed();
111 break;
112 case PERSONAL_PROFILE_SHARE_BLOCKER:
113 assertCantSharePersonalAppsBlockerDisplayed();
114 break;
115 case WORK_PROFILE_SHARE_BLOCKER:
116 assertCantShareWorkAppsBlockerDisplayed();
117 break;
118 case PERSONAL_PROFILE_ACCESS_BLOCKER:
119 assertCantAccessPersonalAppsBlockerDisplayed();
120 break;
121 case WORK_PROFILE_ACCESS_BLOCKER:
122 assertCantAccessWorkAppsBlockerDisplayed();
123 break;
124 }
125 }
126
127 @Parameterized.Parameters(name = "{0}")
128 public static Collection tests() {
129 return Arrays.asList(
130 new TestCase(
131 /* isSendAction= */ true,
132 /* hasCrossProfileIntents= */ true,
133 /* myUserHandle= */ WORK_USER_HANDLE,
134 /* tab= */ WORK,
135 /* expectedBlocker= */ NO_BLOCKER
136 ),
Andrey Epinf9a8f402022-11-28 11:54:33 -0800137 new TestCase(
138 /* isSendAction= */ true,
139 /* hasCrossProfileIntents= */ false,
140 /* myUserHandle= */ WORK_USER_HANDLE,
141 /* tab= */ WORK,
142 /* expectedBlocker= */ NO_BLOCKER
143 ),
Nick Chameyev0919a832022-10-10 12:39:19 +0000144 new TestCase(
145 /* isSendAction= */ true,
146 /* hasCrossProfileIntents= */ true,
147 /* myUserHandle= */ PERSONAL_USER_HANDLE,
148 /* tab= */ WORK,
149 /* expectedBlocker= */ NO_BLOCKER
150 ),
151 new TestCase(
152 /* isSendAction= */ true,
153 /* hasCrossProfileIntents= */ false,
154 /* myUserHandle= */ PERSONAL_USER_HANDLE,
155 /* tab= */ WORK,
156 /* expectedBlocker= */ WORK_PROFILE_SHARE_BLOCKER
157 ),
158 new TestCase(
159 /* isSendAction= */ true,
160 /* hasCrossProfileIntents= */ true,
161 /* myUserHandle= */ WORK_USER_HANDLE,
162 /* tab= */ PERSONAL,
163 /* expectedBlocker= */ NO_BLOCKER
164 ),
Andrey Epinf9a8f402022-11-28 11:54:33 -0800165 new TestCase(
166 /* isSendAction= */ true,
167 /* hasCrossProfileIntents= */ false,
168 /* myUserHandle= */ WORK_USER_HANDLE,
169 /* tab= */ PERSONAL,
170 /* expectedBlocker= */ PERSONAL_PROFILE_SHARE_BLOCKER
171 ),
Nick Chameyev0919a832022-10-10 12:39:19 +0000172 new TestCase(
173 /* isSendAction= */ true,
174 /* hasCrossProfileIntents= */ true,
175 /* myUserHandle= */ PERSONAL_USER_HANDLE,
176 /* tab= */ PERSONAL,
177 /* expectedBlocker= */ NO_BLOCKER
178 ),
179 new TestCase(
180 /* isSendAction= */ true,
181 /* hasCrossProfileIntents= */ false,
182 /* myUserHandle= */ PERSONAL_USER_HANDLE,
183 /* tab= */ PERSONAL,
184 /* expectedBlocker= */ NO_BLOCKER
185 ),
186 new TestCase(
187 /* isSendAction= */ false,
188 /* hasCrossProfileIntents= */ true,
189 /* myUserHandle= */ WORK_USER_HANDLE,
190 /* tab= */ WORK,
191 /* expectedBlocker= */ NO_BLOCKER
192 ),
193 new TestCase(
194 /* isSendAction= */ false,
195 /* hasCrossProfileIntents= */ false,
196 /* myUserHandle= */ WORK_USER_HANDLE,
197 /* tab= */ WORK,
198 /* expectedBlocker= */ NO_BLOCKER
199 ),
200 new TestCase(
201 /* isSendAction= */ false,
202 /* hasCrossProfileIntents= */ true,
203 /* myUserHandle= */ PERSONAL_USER_HANDLE,
204 /* tab= */ WORK,
205 /* expectedBlocker= */ NO_BLOCKER
206 ),
207 new TestCase(
208 /* isSendAction= */ false,
209 /* hasCrossProfileIntents= */ false,
210 /* myUserHandle= */ PERSONAL_USER_HANDLE,
211 /* tab= */ WORK,
212 /* expectedBlocker= */ WORK_PROFILE_ACCESS_BLOCKER
213 ),
214 new TestCase(
215 /* isSendAction= */ false,
216 /* hasCrossProfileIntents= */ true,
217 /* myUserHandle= */ WORK_USER_HANDLE,
218 /* tab= */ PERSONAL,
219 /* expectedBlocker= */ NO_BLOCKER
220 ),
221 new TestCase(
222 /* isSendAction= */ false,
223 /* hasCrossProfileIntents= */ false,
224 /* myUserHandle= */ WORK_USER_HANDLE,
225 /* tab= */ PERSONAL,
226 /* expectedBlocker= */ PERSONAL_PROFILE_ACCESS_BLOCKER
227 ),
228 new TestCase(
229 /* isSendAction= */ false,
230 /* hasCrossProfileIntents= */ true,
231 /* myUserHandle= */ PERSONAL_USER_HANDLE,
232 /* tab= */ PERSONAL,
233 /* expectedBlocker= */ NO_BLOCKER
234 ),
235 new TestCase(
236 /* isSendAction= */ false,
237 /* hasCrossProfileIntents= */ false,
238 /* myUserHandle= */ PERSONAL_USER_HANDLE,
239 /* tab= */ PERSONAL,
240 /* expectedBlocker= */ NO_BLOCKER
241 )
242 );
243 }
244
245 private List<ResolvedComponentInfo> createResolvedComponentsForTestWithOtherProfile(
246 int numberOfResults, int userId) {
247 List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
248 for (int i = 0; i < numberOfResults; i++) {
249 infoList.add(
250 ResolverDataProvider.createResolvedComponentInfoWithOtherId(i, userId));
251 }
252 return infoList;
253 }
254
255 private List<ResolvedComponentInfo> createResolvedComponentsForTest(int numberOfResults) {
256 List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
257 for (int i = 0; i < numberOfResults; i++) {
258 infoList.add(ResolverDataProvider.createResolvedComponentInfo(i));
259 }
260 return infoList;
261 }
262
263 private void setUpPersonalAndWorkComponentInfos() {
264 markWorkProfileUserAvailable();
265 int workProfileTargets = 4;
266 List<ResolvedComponentInfo> personalResolvedComponentInfos =
267 createResolvedComponentsForTestWithOtherProfile(3,
268 /* userId */ WORK_USER_HANDLE.getIdentifier());
269 List<ResolvedComponentInfo> workResolvedComponentInfos =
270 createResolvedComponentsForTest(workProfileTargets);
271 setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
272 }
273
274 private void setupResolverControllers(
275 List<ResolvedComponentInfo> personalResolvedComponentInfos,
276 List<ResolvedComponentInfo> workResolvedComponentInfos) {
277 when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
278 Mockito.anyBoolean(),
279 Mockito.anyBoolean(),
280 Mockito.isA(List.class)))
281 .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
282 when(sOverrides.workResolverListController.getResolversForIntent(Mockito.anyBoolean(),
283 Mockito.anyBoolean(),
284 Mockito.anyBoolean(),
285 Mockito.isA(List.class))).thenReturn(workResolvedComponentInfos);
286 when(sOverrides.workResolverListController.getResolversForIntentAsUser(Mockito.anyBoolean(),
287 Mockito.anyBoolean(),
288 Mockito.anyBoolean(),
289 Mockito.isA(List.class),
290 eq(UserHandle.SYSTEM)))
291 .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
292 }
293
294 private void waitForIdle() {
295 InstrumentationRegistry.getInstrumentation().waitForIdleSync();
296 }
297
298 private void markWorkProfileUserAvailable() {
299 ChooserWrapperActivity.sOverrides.workProfileUserHandle = WORK_USER_HANDLE;
300 }
301
302 private void assertCantAccessWorkAppsBlockerDisplayed() {
303 onView(withText(R.string.resolver_cross_profile_blocked))
304 .check(matches(isDisplayed()));
305 onView(withText(R.string.resolver_cant_access_work_apps_explanation))
306 .check(matches(isDisplayed()));
307 }
308
309 private void assertCantAccessPersonalAppsBlockerDisplayed() {
310 onView(withText(R.string.resolver_cross_profile_blocked))
311 .check(matches(isDisplayed()));
312 onView(withText(R.string.resolver_cant_access_personal_apps_explanation))
313 .check(matches(isDisplayed()));
314 }
315
316 private void assertCantShareWorkAppsBlockerDisplayed() {
317 onView(withText(R.string.resolver_cross_profile_blocked))
318 .check(matches(isDisplayed()));
319 onView(withText(R.string.resolver_cant_share_with_work_apps_explanation))
320 .check(matches(isDisplayed()));
321 }
322
323 private void assertCantSharePersonalAppsBlockerDisplayed() {
324 onView(withText(R.string.resolver_cross_profile_blocked))
325 .check(matches(isDisplayed()));
326 onView(withText(R.string.resolver_cant_share_with_personal_apps_explanation))
327 .check(matches(isDisplayed()));
328 }
329
330 private void assertNoBlockerDisplayed() {
331 try {
332 onView(withText(R.string.resolver_cross_profile_blocked))
333 .check(matches(not(isDisplayed())));
334 } catch (NoMatchingViewException ignored) {
335 }
336 }
337
338 private void switchToTab(Tab tab) {
339 final int stringId = tab == Tab.WORK ? R.string.resolver_work_tab
340 : R.string.resolver_personal_tab;
341
Nick Chameyev76e02782022-12-21 15:58:32 +0000342 waitFor(() -> {
343 onView(withText(stringId)).perform(click());
344 waitForIdle();
345
346 try {
347 onView(withText(stringId)).check(matches(isSelected()));
348 return true;
349 } catch (AssertionFailedError e) {
350 return false;
351 }
352 });
Nick Chameyev0919a832022-10-10 12:39:19 +0000353
354 onView(withId(R.id.contentPanel))
355 .perform(swipeUp());
356 waitForIdle();
357 }
358
359 private Intent createTextIntent(boolean isSendAction) {
360 Intent sendIntent = new Intent();
361 if (isSendAction) {
362 sendIntent.setAction(Intent.ACTION_SEND);
363 }
364 sendIntent.putExtra(Intent.EXTRA_TEXT, "testing intent sending");
365 sendIntent.setType("text/plain");
366 return sendIntent;
367 }
368
369 private void launchActivity(boolean isSendAction) {
370 Intent sendIntent = createTextIntent(isSendAction);
371 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "Test"));
372 waitForIdle();
373 }
374
375 public static class TestCase {
376 private final boolean mIsSendAction;
377 private final boolean mHasCrossProfileIntents;
378 private final UserHandle mMyUserHandle;
379 private final Tab mTab;
380 private final ExpectedBlocker mExpectedBlocker;
381
382 public enum ExpectedBlocker {
383 NO_BLOCKER,
384 PERSONAL_PROFILE_SHARE_BLOCKER,
385 WORK_PROFILE_SHARE_BLOCKER,
386 PERSONAL_PROFILE_ACCESS_BLOCKER,
387 WORK_PROFILE_ACCESS_BLOCKER
388 }
389
390 public enum Tab {
391 WORK,
392 PERSONAL
393 }
394
395 public TestCase(boolean isSendAction, boolean hasCrossProfileIntents,
396 UserHandle myUserHandle, Tab tab, ExpectedBlocker expectedBlocker) {
397 mIsSendAction = isSendAction;
398 mHasCrossProfileIntents = hasCrossProfileIntents;
399 mMyUserHandle = myUserHandle;
400 mTab = tab;
401 mExpectedBlocker = expectedBlocker;
402 }
403
404 public boolean getIsSendAction() {
405 return mIsSendAction;
406 }
407
408 public boolean hasCrossProfileIntents() {
409 return mHasCrossProfileIntents;
410 }
411
412 public UserHandle getMyUserHandle() {
413 return mMyUserHandle;
414 }
415
416 public Tab getTab() {
417 return mTab;
418 }
419
420 public ExpectedBlocker getExpectedBlocker() {
421 return mExpectedBlocker;
422 }
423
424 @Override
425 public String toString() {
426 StringBuilder result = new StringBuilder("test");
427
428 if (mTab == WORK) {
429 result.append("WorkTab_");
430 } else {
431 result.append("PersonalTab_");
432 }
433
434 if (mIsSendAction) {
435 result.append("sendAction_");
436 } else {
437 result.append("notSendAction_");
438 }
439
440 if (mHasCrossProfileIntents) {
441 result.append("hasCrossProfileIntents_");
442 } else {
443 result.append("doesNotHaveCrossProfileIntents_");
444 }
445
446 if (mMyUserHandle.equals(PERSONAL_USER_HANDLE)) {
447 result.append("myUserIsPersonal_");
448 } else {
449 result.append("myUserIsWork_");
450 }
451
452 if (mExpectedBlocker == ExpectedBlocker.NO_BLOCKER) {
453 result.append("thenNoBlocker");
454 } else if (mExpectedBlocker == PERSONAL_PROFILE_ACCESS_BLOCKER) {
455 result.append("thenAccessBlockerOnPersonalProfile");
456 } else if (mExpectedBlocker == PERSONAL_PROFILE_SHARE_BLOCKER) {
457 result.append("thenShareBlockerOnPersonalProfile");
458 } else if (mExpectedBlocker == WORK_PROFILE_ACCESS_BLOCKER) {
459 result.append("thenAccessBlockerOnWorkProfile");
460 } else if (mExpectedBlocker == WORK_PROFILE_SHARE_BLOCKER) {
461 result.append("thenShareBlockerOnWorkProfile");
462 }
463
464 return result.toString();
465 }
466 }
467}