1 /*
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 package com.android.server.pm;
17 
18 import static android.os.UserHandle.USER_ALL;
19 import static android.os.UserHandle.USER_CURRENT;
20 import static android.os.UserHandle.USER_CURRENT_OR_SELF;
21 import static android.os.UserHandle.USER_NULL;
22 import static android.os.UserHandle.USER_SYSTEM;
23 import static android.view.Display.DEFAULT_DISPLAY;
24 import static android.view.Display.INVALID_DISPLAY;
25 
26 import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_FAILURE;
27 import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE;
28 import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE;
29 import static com.android.server.pm.UserManagerInternal.USER_START_MODE_BACKGROUND;
30 import static com.android.server.pm.UserManagerInternal.USER_START_MODE_BACKGROUND_VISIBLE;
31 import static com.android.server.pm.UserManagerInternal.USER_START_MODE_FOREGROUND;
32 import static com.android.server.pm.UserManagerInternal.userAssignmentResultToString;
33 import static com.android.server.pm.UserVisibilityChangedEvent.onInvisible;
34 import static com.android.server.pm.UserVisibilityChangedEvent.onVisible;
35 import static com.android.server.pm.UserVisibilityMediator.INITIAL_CURRENT_USER_ID;
36 
37 import static com.google.common.truth.Truth.assertWithMessage;
38 
39 import static org.junit.Assert.assertThrows;
40 
41 import android.annotation.UserIdInt;
42 import android.os.Handler;
43 import android.text.TextUtils;
44 import android.util.IntArray;
45 import android.util.Log;
46 
47 import com.android.server.DumpableDumperRule;
48 import com.android.server.ExpectableTestCase;
49 
50 import org.junit.Before;
51 import org.junit.Test;
52 
53 import java.util.Arrays;
54 
55 /**
56  * Base class for {@link UserVisibilityMediator} tests.
57  *
58  * <p>It contains common logics and tests for behaviors that should be invariant regardless of the
59  * device mode (for example, whether the device supports concurrent multiple users on multiple
60  * displays or not).
61  *
62  * <p><P>NOTE: <p> rather than adopting the "one test case for method approach", this class (and
63  * its subclass) adds "one test case for scenario" approach, so it can test many properties (if user
64  * is visible, display associated to the user, etc...) for each scenario (full user started on fg,
65  * profile user started on bg, etc...).
66  */
67 abstract class UserVisibilityMediatorTestCase extends ExpectableTestCase {
68 
69     private static final String TAG = UserVisibilityMediatorTestCase.class.getSimpleName();
70 
71     /**
72      * Id for a simple user (that doesn't have profiles).
73      */
74     protected static final int USER_ID = 600;
75 
76     /**
77      * Id for another simple user.
78      */
79     protected static final int OTHER_USER_ID = 666;
80 
81     /**
82      * Id for yeat another simple user.
83      */
84     protected static final int YET_ANOTHER_USER_ID = 700;
85 
86     /**
87      * Id for a user that has one profile (whose id is {@link #PROFILE_USER_ID}.
88      *
89      * <p>You can use {@link #addDefaultProfileAndParent()} to add both of this user to the service.
90      */
91     protected static final int PARENT_USER_ID = 642;
92 
93     /**
94      * Id for a profile whose parent is {@link #PARENTUSER_ID}.
95      *
96      * <p>You can use {@link #addDefaultProfileAndParent()} to add both of this user to the service.
97      */
98     protected static final int PROFILE_USER_ID = 643;
99 
100     /**
101      * Id of a secondary display (i.e, not {@link android.view.Display.DEFAULT_DISPLAY}).
102      */
103     protected static final int SECONDARY_DISPLAY_ID = 42;
104 
105     /**
106      * Id of another secondary display (i.e, not {@link android.view.Display.DEFAULT_DISPLAY}).
107      */
108     protected static final int OTHER_SECONDARY_DISPLAY_ID = 108;
109 
110     protected static final int FG = USER_START_MODE_FOREGROUND;
111     protected static final int BG = USER_START_MODE_BACKGROUND;
112     protected static final int BG_VISIBLE = USER_START_MODE_BACKGROUND_VISIBLE;
113 
114     private Handler mHandler;
115     protected AsyncUserVisibilityListener.Factory mListenerFactory;
116 
117     private final boolean mBackgroundUsersOnDisplaysEnabled;
118     private final boolean mBackgroundUserOnDefaultDisplayAllowed;
119 
120     protected UserVisibilityMediator mMediator;
121 
UserVisibilityMediatorTestCase(boolean backgroundUsersOnDisplaysEnabled, boolean backgroundUserOnDefaultDisplayAllowed)122     protected UserVisibilityMediatorTestCase(boolean backgroundUsersOnDisplaysEnabled,
123             boolean backgroundUserOnDefaultDisplayAllowed) {
124         mBackgroundUsersOnDisplaysEnabled = backgroundUsersOnDisplaysEnabled;
125         mBackgroundUserOnDefaultDisplayAllowed = backgroundUserOnDefaultDisplayAllowed;
126     }
127 
128     protected final DumpableDumperRule mDumpableDumperRule = new DumpableDumperRule();
129 
130     @Before
setFixtures()131     public final void setFixtures() {
132         mHandler = Handler.getMain();
133         Thread thread = mHandler.getLooper().getThread();
134         Log.i(TAG, "setFixtures(): using thread " + thread + " (from handler " + mHandler + ")");
135         mListenerFactory = new AsyncUserVisibilityListener.Factory(mExpect, thread);
136         mMediator = new UserVisibilityMediator(mBackgroundUsersOnDisplaysEnabled,
137                 mBackgroundUserOnDefaultDisplayAllowed, mHandler);
138         mDumpableDumperRule.addDumpable(mMediator);
139     }
140 
141     @Test
testInvalidMode()142     public void testInvalidMode() {
143         assertThrows(IllegalArgumentException.class, () -> new UserVisibilityMediator(
144                 /* visibleBackgroundUsersOnDisplaysEnabled= */ false,
145                 /* visibleBackgroundUserOnDefaultDisplayAllowed= */ true, mHandler));
146     }
147 
148     @Test
testAssignUserToDisplayOnStart_invalidUserIds()149     public final void testAssignUserToDisplayOnStart_invalidUserIds() {
150         assertThrows(IllegalArgumentException.class, () -> mMediator
151                 .assignUserToDisplayOnStart(USER_NULL, USER_ID, FG, DEFAULT_DISPLAY, false));
152         assertThrows(IllegalArgumentException.class, () -> mMediator
153                 .assignUserToDisplayOnStart(USER_ALL, USER_ID, FG, DEFAULT_DISPLAY, false));
154         assertThrows(IllegalArgumentException.class, () -> mMediator
155                 .assignUserToDisplayOnStart(USER_CURRENT, USER_ID, FG, DEFAULT_DISPLAY, false));
156         assertThrows(IllegalArgumentException.class, () -> mMediator
157                 .assignUserToDisplayOnStart(USER_CURRENT_OR_SELF, USER_ID, FG, DEFAULT_DISPLAY,
158                         false));
159     }
160 
161     @Test
testAssignUserToDisplayOnStart_invalidUserStartMode()162     public final void testAssignUserToDisplayOnStart_invalidUserStartMode() {
163         assertThrows(IllegalArgumentException.class, () -> mMediator
164                 .assignUserToDisplayOnStart(USER_ID, USER_ID, 666, DEFAULT_DISPLAY, false));
165     }
166 
167     @Test
testStartFgUser_onSecondaryDisplay()168     public final void testStartFgUser_onSecondaryDisplay() throws Exception {
169         AsyncUserVisibilityListener listener = addListenerForNoEvents();
170 
171         int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, FG,
172                 SECONDARY_DISPLAY_ID, false);
173         assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
174 
175         expectUserIsNotVisibleAtAll(USER_ID);
176         expectNoDisplayAssignedToUser(USER_ID);
177         expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY);
178 
179         listener.verify();
180     }
181 
182     @Test
testStartBgUser_onDefaultDisplay()183     public final void testStartBgUser_onDefaultDisplay() throws Exception {
184         AsyncUserVisibilityListener listener = addListenerForNoEvents();
185 
186         int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, BG, DEFAULT_DISPLAY,
187                 false);
188         assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE);
189 
190         expectUserIsNotVisibleAtAll(USER_ID);
191         expectNoDisplayAssignedToUser(USER_ID);
192         expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY);
193 
194         assertInvisibleUserCannotBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID);
195 
196         listener.verify();
197     }
198 
visibleBgUserCannotBeStartedOnDefaultDisplayTest()199     protected final @UserIdInt int visibleBgUserCannotBeStartedOnDefaultDisplayTest()
200             throws Exception {
201         AsyncUserVisibilityListener listener = addListenerForNoEvents();
202 
203         int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, BG_VISIBLE,
204                 DEFAULT_DISPLAY, false);
205         assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
206 
207         expectUserIsNotVisibleAtAll(USER_ID);
208         expectNoDisplayAssignedToUser(USER_ID);
209 
210         listener.verify();
211 
212         return USER_ID;
213     }
214 
215     @Test
testStartBgUser_onSecondaryDisplay()216     public final void testStartBgUser_onSecondaryDisplay() throws Exception {
217         AsyncUserVisibilityListener listener = addListenerForNoEvents();
218 
219         int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, BG,
220                 SECONDARY_DISPLAY_ID, false);
221         assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
222 
223         expectUserIsNotVisibleAtAll(USER_ID);
224         expectNoDisplayAssignedToUser(USER_ID);
225 
226         assertInvisibleUserCannotBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID);
227         assertInvisibleUserCannotBeAssignedExtraDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID);
228 
229         listener.verify();
230     }
231 
232     @Test
testStartBgSystemUser_onSecondaryDisplay()233     public final void testStartBgSystemUser_onSecondaryDisplay() throws Exception {
234         AsyncUserVisibilityListener listener = addListenerForEvents(
235                 onInvisible(INITIAL_CURRENT_USER_ID),
236                 onVisible(USER_ID));
237         // Must explicitly set current user, as USER_SYSTEM is the default current user
238         startForegroundUser(USER_ID);
239 
240         int result = mMediator.assignUserToDisplayOnStart(USER_SYSTEM, USER_SYSTEM, BG,
241                 SECONDARY_DISPLAY_ID, false);
242         assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
243 
244         expectUserIsNotVisibleAtAll(USER_SYSTEM);
245 
246         expectNoDisplayAssignedToUser(USER_SYSTEM);
247         expectUserAssignedToDisplay(SECONDARY_DISPLAY_ID, USER_ID);
248 
249         assertUserCannotBeAssignedExtraDisplay(USER_SYSTEM, SECONDARY_DISPLAY_ID);
250         assertUserCannotBeAssignedExtraDisplay(USER_SYSTEM, OTHER_SECONDARY_DISPLAY_ID);
251 
252         listener.verify();
253     }
254 
255     @Test
testStopVisibleBgProfile()256     public final void testStopVisibleBgProfile() throws Exception {
257         AsyncUserVisibilityListener listener = addListenerForEvents(
258                 onInvisible(INITIAL_CURRENT_USER_ID),
259                 onVisible(PARENT_USER_ID),
260                 onVisible(PROFILE_USER_ID),
261                 onInvisible(PROFILE_USER_ID));
262         startDefaultProfile();
263 
264         mMediator.unassignUserFromDisplayOnStop(PROFILE_USER_ID);
265 
266         expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
267         expectNoDisplayAssignedToUser(PROFILE_USER_ID);
268         expectUserAssignedToDisplay(DEFAULT_DISPLAY, PARENT_USER_ID);
269 
270         listener.verify();
271     }
272 
273     @Test
testVisibleBgProfileBecomesInvisibleWhenParentIsSwitchedOut()274     public final void testVisibleBgProfileBecomesInvisibleWhenParentIsSwitchedOut()
275             throws Exception {
276         AsyncUserVisibilityListener listener = addListenerForEvents(
277                 onInvisible(INITIAL_CURRENT_USER_ID),
278                 onVisible(PARENT_USER_ID),
279                 onVisible(PROFILE_USER_ID),
280                 onInvisible(PARENT_USER_ID),
281                 onInvisible(PROFILE_USER_ID),
282                 onVisible(OTHER_USER_ID));
283         startDefaultProfile();
284 
285         startForegroundUser(OTHER_USER_ID);
286 
287         expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
288         expectNoDisplayAssignedToUser(PROFILE_USER_ID);
289         expectUserAssignedToDisplay(DEFAULT_DISPLAY, OTHER_USER_ID);
290 
291         assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
292 
293         listener.verify();
294     }
295 
296     @Test
testStartVisibleBgProfile_onDefaultDisplay_whenParentIsNotStarted()297     public final void testStartVisibleBgProfile_onDefaultDisplay_whenParentIsNotStarted()
298             throws Exception {
299         AsyncUserVisibilityListener listener = addListenerForNoEvents();
300 
301         int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
302                 BG_VISIBLE, DEFAULT_DISPLAY, false);
303         assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
304 
305         expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
306         expectNoDisplayAssignedToUser(PROFILE_USER_ID);
307 
308         listener.verify();
309     }
310 
311     @Test
testStartVisibleBgProfile_onDefaultDisplay_whenParentIsStartedOnBg()312     public final void testStartVisibleBgProfile_onDefaultDisplay_whenParentIsStartedOnBg()
313             throws Exception {
314         AsyncUserVisibilityListener listener = addListenerForNoEvents();
315         startBackgroundUser(PARENT_USER_ID);
316 
317         int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
318                 BG_VISIBLE, DEFAULT_DISPLAY, false);
319         assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
320 
321         expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
322 
323         expectNoDisplayAssignedToUser(PROFILE_USER_ID);
324         expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY);
325 
326         assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
327 
328         listener.verify();
329     }
330 
331     // Not supported - profiles can only be started on default display
332     @Test
testStartVisibleBgProfile_onSecondaryDisplay()333     public final void testStartVisibleBgProfile_onSecondaryDisplay() throws Exception {
334         AsyncUserVisibilityListener listener = addListenerForNoEvents();
335 
336         int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
337                 BG_VISIBLE, SECONDARY_DISPLAY_ID, false);
338         assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
339 
340         expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
341         expectNoDisplayAssignedToUser(PROFILE_USER_ID);
342         expectInitialCurrentUserAssignedToDisplay(SECONDARY_DISPLAY_ID);
343 
344         assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
345         assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID,
346                 OTHER_SECONDARY_DISPLAY_ID);
347 
348         listener.verify();
349     }
350 
351     @Test
testStartBgProfile_onDefaultDisplay_whenParentIsNotStarted()352     public final void testStartBgProfile_onDefaultDisplay_whenParentIsNotStarted()
353             throws Exception {
354         AsyncUserVisibilityListener listener = addListenerForNoEvents();
355 
356         int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG,
357                 DEFAULT_DISPLAY, false);
358         assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE);
359 
360         expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
361         expectNoDisplayAssignedToUser(PROFILE_USER_ID);
362 
363         listener.verify();
364     }
365 
366     @Test
testStartBgProfile_onDefaultDisplay_whenParentIsStartedOnBg()367     public final void testStartBgProfile_onDefaultDisplay_whenParentIsStartedOnBg()
368             throws Exception {
369         AsyncUserVisibilityListener listener = addListenerForNoEvents();
370         startBackgroundUser(PARENT_USER_ID);
371 
372         int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG,
373                 DEFAULT_DISPLAY, false);
374         assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE);
375 
376         expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
377 
378         expectNoDisplayAssignedToUser(PROFILE_USER_ID);
379         expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY);
380 
381         assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
382 
383         listener.verify();
384     }
385 
386     @Test
testStartBgProfile_onSecondaryDisplay()387     public final void testStartBgProfile_onSecondaryDisplay() throws Exception {
388         AsyncUserVisibilityListener listener = addListenerForNoEvents();
389 
390         int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG,
391                 SECONDARY_DISPLAY_ID, false);
392         assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
393 
394         expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
395         expectNoDisplayAssignedToUser(PROFILE_USER_ID);
396         expectInitialCurrentUserAssignedToDisplay(SECONDARY_DISPLAY_ID);
397 
398         assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
399         assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID,
400                 OTHER_SECONDARY_DISPLAY_ID);
401 
402         listener.verify();
403     }
404 
405     @Test
testStartFgProfile_onDefaultDisplay()406     public final void testStartFgProfile_onDefaultDisplay() throws Exception {
407         AsyncUserVisibilityListener listener = addListenerForNoEvents();
408 
409         int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, FG,
410                 DEFAULT_DISPLAY, false);
411         assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
412 
413         expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
414 
415         expectNoDisplayAssignedToUser(PROFILE_USER_ID);
416         expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY);
417 
418         assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY);
419         assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
420 
421         listener.verify();
422     }
423 
424     @Test
testStartFgProfile_onSecondaryDisplay()425     public final void testStartFgProfile_onSecondaryDisplay() throws Exception {
426         AsyncUserVisibilityListener listener = addListenerForNoEvents();
427 
428         int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, FG,
429                 SECONDARY_DISPLAY_ID, false);
430         assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
431 
432         expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
433         expectNoDisplayAssignedToUser(PROFILE_USER_ID);
434         expectInitialCurrentUserAssignedToDisplay(SECONDARY_DISPLAY_ID);
435 
436         assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
437         assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID,
438                 OTHER_SECONDARY_DISPLAY_ID);
439 
440         listener.verify();
441     }
442 
443     @Test
testIsUserVisible_invalidUsers()444     public final void testIsUserVisible_invalidUsers() throws Exception {
445         expectWithMessage("isUserVisible(%s)", USER_NULL)
446                 .that(mMediator.isUserVisible(USER_NULL))
447                 .isFalse();
448         expectWithMessage("isUserVisible(%s)", USER_NULL)
449                 .that(mMediator.isUserVisible(USER_ALL))
450                 .isFalse();
451         expectWithMessage("isUserVisible(%s)", USER_NULL)
452                 .that(mMediator.isUserVisible(USER_CURRENT))
453                 .isFalse();
454         expectWithMessage("isUserVisible(%s)", USER_NULL)
455                 .that(mMediator.isUserVisible(USER_CURRENT_OR_SELF))
456                 .isFalse();
457     }
458 
459     @Test
testRemoveListener()460     public final void testRemoveListener() throws Exception {
461         AsyncUserVisibilityListener listener = addListenerForNoEvents();
462 
463         mMediator.removeListener(listener);
464 
465         startForegroundUser(USER_ID);
466         listener.verify();
467     }
468 
469     @Test
testOnSystemUserVisibilityChanged()470     public final void testOnSystemUserVisibilityChanged() throws Exception {
471         AsyncUserVisibilityListener listener = addListenerForEvents(onVisible(USER_SYSTEM));
472 
473         mMediator.onSystemUserVisibilityChanged(/* visible= */ true);
474 
475         listener.verify();
476     }
477 
478     /**
479      * Starts a user in foreground on the default display, asserting it was properly started.
480      *
481      * <p><b>NOTE: </b>should only be used as a helper method, not to test the behavior of the
482      * {@link UserVisibilityMediator#assignUserToDisplayOnStart(int, int, boolean, int)} method per
483      * se.
484      */
startForegroundUser(@serIdInt int userId)485     protected void startForegroundUser(@UserIdInt int userId) {
486         Log.d(TAG, "startForegroundUSer(" + userId + ")");
487         int result = mMediator.assignUserToDisplayOnStart(userId, userId, FG, DEFAULT_DISPLAY,
488                 false);
489         if (result != USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE) {
490             throw new IllegalStateException("Failed to start foreground user " + userId
491                     + ": mediator returned " + userAssignmentResultToString(result));
492         }
493     }
494 
495     /**
496      * Starts a user in background on the default display, asserting it was properly started.
497      *
498      * <p><b>NOTE: </b>should only be used as a helper method, not to test the behavior of the
499      * {@link UserVisibilityMediator#assignUserToDisplayOnStart(int, int, boolean, int)} method per
500      * se.
501      */
startBackgroundUser(@serIdInt int userId)502     protected void startBackgroundUser(@UserIdInt int userId) {
503         Log.d(TAG, "startBackgroundUser(" + userId + ")");
504         int result = mMediator.assignUserToDisplayOnStart(userId, userId, BG, DEFAULT_DISPLAY,
505                 false);
506         if (result != USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE) {
507             throw new IllegalStateException("Failed to start background user " + userId
508                     + ": mediator returned " + userAssignmentResultToString(result));
509         }
510     }
511 
512     /**
513      * Starts the {@link #PROFILE_USER_ID default profile} in background and its
514      * {@link #PARENT_USER_ID parent} in foreground on the main display, asserting that
515      * both were properly started.
516      *
517      * <p><b>NOTE: </b>should only be used as a helper method, not to test the behavior of the
518      * {@link UserVisibilityMediator#assignUserToDisplayOnStart(int, int, boolean, int)} method per
519      * se.
520      */
startDefaultProfile()521     protected void startDefaultProfile() {
522         startForegroundUser(PARENT_USER_ID);
523         Log.d(TAG, "starting default profile (" + PROFILE_USER_ID + ") in background after starting"
524                 + " its parent (" + PARENT_USER_ID + ") on foreground");
525 
526         int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
527                 BG_VISIBLE, DEFAULT_DISPLAY, false);
528         if (result != USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE) {
529             throw new IllegalStateException("Failed to start profile user " + PROFILE_USER_ID
530                     + ": mediator returned " + userAssignmentResultToString(result));
531         }
532     }
533 
534     /**
535      * Starts a user in background on the secondary display, asserting it was properly started.
536      *
537      * <p><b>NOTE: </b>should only be used as a helper method, not to test the behavior of the
538      * {@link UserVisibilityMediator#assignUserToDisplayOnStart(int, int, boolean, int)} method per
539      * se.
540      */
startUserInSecondaryDisplay(@serIdInt int userId, int displayId)541     protected final void startUserInSecondaryDisplay(@UserIdInt int userId, int displayId) {
542         Log.d(TAG, "startUserInSecondaryDisplay(" + userId + ", " + displayId + ")");
543         int result = mMediator.assignUserToDisplayOnStart(userId, userId, BG_VISIBLE, displayId,
544                 false);
545         if (result != USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE) {
546             throw new IllegalStateException("Failed to startuser " + userId
547                     + " on background: mediator returned " + userAssignmentResultToString(result));
548         }
549     }
550 
addListenerForNoEvents()551     protected AsyncUserVisibilityListener addListenerForNoEvents() {
552         AsyncUserVisibilityListener listener = mListenerFactory.forNoEvents();
553         mMediator.addListener(listener);
554         return listener;
555     }
556 
addListenerForEvents( UserVisibilityChangedEvent... events)557     protected AsyncUserVisibilityListener addListenerForEvents(
558             UserVisibilityChangedEvent... events) {
559         AsyncUserVisibilityListener listener = mListenerFactory.forEvents(events);
560         mMediator.addListener(listener);
561         return listener;
562     }
563 
assertStartUserResult(int actualResult, int expectedResult)564     protected void assertStartUserResult(int actualResult, int expectedResult) {
565         assertStartUserResult(actualResult, expectedResult, "");
566     }
567 
568     @SuppressWarnings("AnnotateFormatMethod")
assertStartUserResult(int actualResult, int expectedResult, String extraMessageFormat, Object... extraMessageArguments)569     protected void assertStartUserResult(int actualResult, int expectedResult,
570             String extraMessageFormat, Object... extraMessageArguments) {
571         String extraMessage = String.format(extraMessageFormat, extraMessageArguments);
572         assertWithMessage("startUser() result %s(where %s=%s and %s=%s)", extraMessage,
573                 expectedResult, userAssignmentResultToString(expectedResult),
574                 actualResult, userAssignmentResultToString(actualResult))
575                         .that(actualResult).isEqualTo(expectedResult);
576     }
577 
assertBgUserBecomesInvisibleOnStop(@serIdInt int userId)578     protected void assertBgUserBecomesInvisibleOnStop(@UserIdInt int userId) {
579         Log.d(TAG, "Stopping user " + userId);
580         mMediator.unassignUserFromDisplayOnStop(userId);
581         expectUserIsNotVisibleAtAll(userId);
582     }
583 
584     /**
585      * Assigns and unassigns the user to / from an extra display, asserting the visibility state in
586      * between.
587      *
588      * <p>It assumes the user was not visible in the display beforehand.
589      */
assertUserCanBeAssignedExtraDisplay(@serIdInt int userId, int displayId)590     protected void assertUserCanBeAssignedExtraDisplay(@UserIdInt int userId, int displayId) {
591         assertUserCanBeAssignedExtraDisplay(userId, displayId, /* unassign= */ true);
592     }
593 
assertUserCanBeAssignedExtraDisplay(@serIdInt int userId, int displayId, boolean unassign)594     protected void assertUserCanBeAssignedExtraDisplay(@UserIdInt int userId, int displayId,
595             boolean unassign) {
596 
597         expectUserIsNotVisibleOnDisplay(userId, displayId);
598 
599         Log.d(TAG, "Calling assignUserToExtraDisplay(" + userId + ", " + displayId + ")");
600         assertWithMessage("assignUserToExtraDisplay(%s, %s)", userId, displayId)
601                 .that(mMediator.assignUserToExtraDisplay(userId, displayId))
602                 .isTrue();
603         expectUserIsVisibleOnDisplay(userId, displayId);
604         expectDisplaysAssignedToUserContainsDisplayId(userId, displayId);
605 
606         if (unassign) {
607             Log.d(TAG, "Calling unassignUserFromExtraDisplay(" + userId + ", " + displayId + ")");
608             assertWithMessage("unassignUserFromExtraDisplay(%s, %s)", userId, displayId)
609                     .that(mMediator.unassignUserFromExtraDisplay(userId, displayId))
610                     .isTrue();
611             expectUserIsNotVisibleOnDisplay(userId, displayId);
612             expectDisplaysAssignedToUserDoesNotContainDisplayId(userId, displayId);
613         }
614     }
615 
616     /**
617      * Asserts that a user (already visible or not) cannot be assigned to an extra display (and
618      * hence won't be visible on that display).
619      */
assertUserCannotBeAssignedExtraDisplay(@serIdInt int userId, int displayId)620     protected void assertUserCannotBeAssignedExtraDisplay(@UserIdInt int userId, int displayId) {
621         expectWithMessage("assignUserToExtraDisplay(%s, %s)", userId, displayId)
622                 .that(mMediator.assignUserToExtraDisplay(userId, displayId))
623                 .isFalse();
624         expectUserIsNotVisibleOnDisplay(userId, displayId);
625     }
626 
627     /**
628      * Asserts that an invisible user cannot be assigned to an extra display.
629      */
assertInvisibleUserCannotBeAssignedExtraDisplay(@serIdInt int userId, int displayId)630     protected void assertInvisibleUserCannotBeAssignedExtraDisplay(@UserIdInt int userId,
631             int displayId) {
632         assertUserCannotBeAssignedExtraDisplay(userId, displayId);
633         expectNoDisplayAssignedToUser(userId);
634         expectInitialCurrentUserAssignedToDisplay(displayId);
635     }
636 
expectUserIsVisible(@serIdInt int userId)637     protected void expectUserIsVisible(@UserIdInt int userId) {
638         expectWithMessage("isUserVisible(%s)", userId)
639                 .that(mMediator.isUserVisible(userId))
640                 .isTrue();
641     }
642 
expectVisibleUsers(@serIdInt Integer... userIds)643     protected void expectVisibleUsers(@UserIdInt Integer... userIds) {
644         IntArray visibleUsers = mMediator.getVisibleUsers();
645         expectWithMessage("getVisibleUsers()").that(visibleUsers).isNotNull();
646         expectWithMessage("getVisibleUsers()").that(visibleUsers.toArray()).asList()
647                 .containsExactlyElementsIn(Arrays.asList(userIds));
648     }
649 
expectUserIsVisibleOnDisplay(@serIdInt int userId, int displayId)650     protected void expectUserIsVisibleOnDisplay(@UserIdInt int userId, int displayId) {
651         expectWithMessage("isUserVisible(%s, %s)", userId, displayId)
652                 .that(mMediator.isUserVisible(userId, displayId))
653                 .isTrue();
654     }
655 
expectUserIsNotVisibleOnDisplay(@serIdInt int userId, int displayId)656     protected void expectUserIsNotVisibleOnDisplay(@UserIdInt int userId, int displayId) {
657         expectWithMessage("isUserVisible(%s, %s)", userId, displayId)
658                 .that(mMediator.isUserVisible(userId, displayId))
659                 .isFalse();
660     }
661 
expectUserIsNotVisibleOnDisplay(String when, @UserIdInt int userId, int displayId)662     protected void expectUserIsNotVisibleOnDisplay(String when, @UserIdInt int userId,
663             int displayId) {
664         String suffix = TextUtils.isEmpty(when) ? "" : " on " + when;
665         expectWithMessage("isUserVisible(%s, %s)%s", userId, displayId, suffix)
666                 .that(mMediator.isUserVisible(userId, displayId))
667                 .isFalse();
668     }
669 
expectUserIsNotVisibleAtAll(@serIdInt int userId)670     protected void expectUserIsNotVisibleAtAll(@UserIdInt int userId) {
671         expectWithMessage("isUserVisible(%s)", userId)
672                 .that(mMediator.isUserVisible(userId))
673                 .isFalse();
674         expectUserIsNotVisibleOnDisplay(userId, DEFAULT_DISPLAY);
675         expectUserIsNotVisibleOnDisplay(userId, INVALID_DISPLAY);
676         expectUserIsNotVisibleOnDisplay(userId, SECONDARY_DISPLAY_ID);
677         expectUserIsNotVisibleOnDisplay(userId, OTHER_SECONDARY_DISPLAY_ID);
678         expectDisplaysAssignedToUserIsEmpty(userId);
679     }
680 
expectDisplayAssignedToUser(@serIdInt int userId, int displayId)681     protected void expectDisplayAssignedToUser(@UserIdInt int userId, int displayId) {
682         expectWithMessage("getMainDisplayAssignedToUser(%s)", userId)
683                 .that(mMediator.getMainDisplayAssignedToUser(userId)).isEqualTo(displayId);
684     }
685 
expectNoDisplayAssignedToUser(@serIdInt int userId)686     protected void expectNoDisplayAssignedToUser(@UserIdInt int userId) {
687         expectWithMessage("getMainDisplayAssignedToUser(%s)", userId)
688                 .that(mMediator.getMainDisplayAssignedToUser(userId)).isEqualTo(INVALID_DISPLAY);
689     }
690 
expectDisplaysAssignedToUserContainsDisplayId( @serIdInt int userId, int displayId)691     protected void expectDisplaysAssignedToUserContainsDisplayId(
692             @UserIdInt int userId, int displayId) {
693         expectWithMessage("getDisplaysAssignedToUser(%s)", userId)
694                 .that(mMediator.getDisplaysAssignedToUser(userId)).asList().contains(displayId);
695     }
696 
expectDisplaysAssignedToUserDoesNotContainDisplayId( @serIdInt int userId, int displayId)697     protected void expectDisplaysAssignedToUserDoesNotContainDisplayId(
698             @UserIdInt int userId, int displayId) {
699         expectWithMessage("getDisplaysAssignedToUser(%s)", userId)
700                 .that(mMediator.getDisplaysAssignedToUser(userId)).asList()
701                 .doesNotContain(displayId);
702     }
703 
expectDisplaysAssignedToUserIsEmpty(@serIdInt int userId)704     protected void expectDisplaysAssignedToUserIsEmpty(@UserIdInt int userId) {
705         expectWithMessage("getDisplaysAssignedToUser(%s)", userId)
706                 .that(mMediator.getDisplaysAssignedToUser(userId)).isNull();
707     }
708 
expectUserCannotBeUnassignedFromDisplay(@serIdInt int userId, int displayId)709     protected void expectUserCannotBeUnassignedFromDisplay(@UserIdInt int userId, int displayId) {
710         expectWithMessage("unassignUserFromExtraDisplay(%s, %s)", userId, displayId)
711                 .that(mMediator.unassignUserFromExtraDisplay(userId, displayId)).isFalse();
712     }
713 
expectUserAssignedToDisplay(int displayId, @UserIdInt int userId)714     protected void expectUserAssignedToDisplay(int displayId, @UserIdInt int userId) {
715         expectWithMessage("getUserAssignedToDisplay(%s)", displayId)
716                 .that(mMediator.getUserAssignedToDisplay(displayId)).isEqualTo(userId);
717     }
718 
expectInitialCurrentUserAssignedToDisplay(int displayId)719     protected void expectInitialCurrentUserAssignedToDisplay(int displayId) {
720         expectWithMessage("getUserAssignedToDisplay(%s)", displayId)
721                 .that(mMediator.getUserAssignedToDisplay(displayId))
722                 .isEqualTo(INITIAL_CURRENT_USER_ID);
723     }
724 }
725