diff --git a/services/core/java/com/android/server/pm/UserVisibilityMediator.java b/services/core/java/com/android/server/pm/UserVisibilityMediator.java index 66d390f4f3e99..1f935f901d5b9 100644 --- a/services/core/java/com/android/server/pm/UserVisibilityMediator.java +++ b/services/core/java/com/android/server/pm/UserVisibilityMediator.java @@ -36,6 +36,7 @@ import android.annotation.UserIdInt; import android.os.Handler; import android.os.UserHandle; import android.os.UserManager; +import android.util.DebugUtils; import android.util.Dumpable; import android.util.EventLog; import android.util.IndentingPrintWriter; @@ -80,6 +81,7 @@ public final class UserVisibilityMediator implements Dumpable { private static final String TAG = UserVisibilityMediator.class.getSimpleName(); + private static final String PREFIX_SECONDARY_DISPLAY_MAPPING = "SECONDARY_DISPLAY_MAPPING_"; public static final int SECONDARY_DISPLAY_MAPPING_NEEDED = 1; public static final int SECONDARY_DISPLAY_MAPPING_NOT_NEEDED = 2; public static final int SECONDARY_DISPLAY_MAPPING_FAILED = -1; @@ -88,7 +90,7 @@ public final class UserVisibilityMediator implements Dumpable { * Whether a user / display assignment requires adding an entry to the * {@code mUsersOnSecondaryDisplays} map. */ - @IntDef(flag = false, prefix = {"SECONDARY_DISPLAY_MAPPING_"}, value = { + @IntDef(flag = false, prefix = {PREFIX_SECONDARY_DISPLAY_MAPPING}, value = { SECONDARY_DISPLAY_MAPPING_NEEDED, SECONDARY_DISPLAY_MAPPING_NOT_NEEDED, SECONDARY_DISPLAY_MAPPING_FAILED @@ -102,6 +104,7 @@ public final class UserVisibilityMediator implements Dumpable { private final Object mLock = new Object(); private final boolean mVisibleBackgroundUsersEnabled; + private final boolean mVisibleBackgroundUserOnDefaultDisplayAllowed; @UserIdInt @GuardedBy("mLock") @@ -110,7 +113,7 @@ public final class UserVisibilityMediator implements Dumpable { /** * Map of background users started visible on displays (key is user id, value is display id). * - *
Only set when {@code mUsersOnSecondaryDisplaysEnabled} is {@code true}. + *
Only set when {@code mVisibleBackgroundUsersEnabled} is {@code true}. */ @Nullable @GuardedBy("mLock") @@ -121,7 +124,7 @@ public final class UserVisibilityMediator implements Dumpable { * {@link #assignUserToExtraDisplay(int, int)}) displays assigned to user (key is display id, * value is user id). * - *
Only set when {@code mUsersOnSecondaryDisplaysEnabled} is {@code true}. + *
Only set when {@code mVisibleBackgroundUsersEnabled} is {@code true}. */ @Nullable @GuardedBy("mLock") @@ -143,12 +146,17 @@ public final class UserVisibilityMediator implements Dumpable { new CopyOnWriteArrayList<>(); UserVisibilityMediator(Handler handler) { - this(UserManager.isVisibleBackgroundUsersEnabled(), handler); + this(UserManager.isVisibleBackgroundUsersEnabled(), + // TODO(b/261538232): get visibleBackgroundUserOnDefaultDisplayAllowed from UM + /* visibleBackgroundUserOnDefaultDisplayAllowed= */ false, handler); } @VisibleForTesting - UserVisibilityMediator(boolean backgroundUsersOnDisplaysEnabled, Handler handler) { + UserVisibilityMediator(boolean backgroundUsersOnDisplaysEnabled, + boolean visibleBackgroundUserOnDefaultDisplayAllowed, Handler handler) { mVisibleBackgroundUsersEnabled = backgroundUsersOnDisplaysEnabled; + mVisibleBackgroundUserOnDefaultDisplayAllowed = + visibleBackgroundUserOnDefaultDisplayAllowed; if (mVisibleBackgroundUsersEnabled) { mUsersAssignedToDisplayOnStart = new SparseIntArray(); mExtraDisplaysAssignedToUsers = new SparseIntArray(); @@ -203,7 +211,12 @@ public final class UserVisibilityMediator implements Dumpable { return result; } - int mappingResult = canAssignUserToDisplayLocked(userId, profileGroupId, displayId); + int mappingResult = canAssignUserToDisplayLocked(userId, profileGroupId, userStartMode, + displayId); + if (DBG) { + Slogf.d(TAG, "mapping result: %s", + secondaryDisplayMappingStatusToString(mappingResult)); + } if (mappingResult == SECONDARY_DISPLAY_MAPPING_FAILED) { return USER_ASSIGNMENT_RESULT_FAILURE; } @@ -263,14 +276,16 @@ public final class UserVisibilityMediator implements Dumpable { + "(it should be BACKGROUND_USER_VISIBLE", userId, displayId); return USER_ASSIGNMENT_RESULT_FAILURE; } - if (userStartMode == USER_START_MODE_BACKGROUND_VISIBLE - && displayId == DEFAULT_DISPLAY && !isProfile(userId, profileGroupId)) { + + boolean visibleBackground = userStartMode == USER_START_MODE_BACKGROUND_VISIBLE; + if (displayId == DEFAULT_DISPLAY && visibleBackground + && !mVisibleBackgroundUserOnDefaultDisplayAllowed + && !isProfile(userId, profileGroupId)) { Slogf.wtf(TAG, "cannot start full user (%d) visible on default display", userId); return USER_ASSIGNMENT_RESULT_FAILURE; } boolean foreground = userStartMode == USER_START_MODE_FOREGROUND; - if (displayId != DEFAULT_DISPLAY) { if (foreground) { Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %b, %d) failed: cannot start " @@ -309,26 +324,47 @@ public final class UserVisibilityMediator implements Dumpable { } return foreground || displayId != DEFAULT_DISPLAY - ? USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE - : USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE; + || (visibleBackground && mVisibleBackgroundUserOnDefaultDisplayAllowed) + ? USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE + : USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE; } @GuardedBy("mLock") @SecondaryDisplayMappingStatus private int canAssignUserToDisplayLocked(@UserIdInt int userId, - @UserIdInt int profileGroupId, int displayId) { - if (displayId == DEFAULT_DISPLAY - && (!mVisibleBackgroundUsersEnabled || !isProfile(userId, profileGroupId))) { - // Don't need to do anything because methods (such as isUserVisible()) already - // know that the current user (and its profiles) is assigned to the default display. - // But on MUMD devices, profiles are only supported in the default display, so it - // cannot return yet as it needs to check if the parent is also assigned to the - // DEFAULT_DISPLAY (this is done indirectly below when it checks that the profile parent - // is the current user, as the current user is always assigned to the DEFAULT_DISPLAY). - if (DBG) { - Slogf.d(TAG, "ignoring mapping for default display"); + @UserIdInt int profileGroupId, @UserStartMode int userStartMode, int displayId) { + if (displayId == DEFAULT_DISPLAY) { + boolean mappingNeeded = false; + if (mVisibleBackgroundUserOnDefaultDisplayAllowed + && userStartMode == USER_START_MODE_BACKGROUND_VISIBLE) { + int userStartedOnDefaultDisplay = getUserStartedOnDisplay(DEFAULT_DISPLAY); + if (userStartedOnDefaultDisplay != USER_NULL) { + Slogf.w(TAG, "getUserVisibilityOnStartLocked(): cannot start user %d visible on" + + " default display because user %d already did so", userId, + userStartedOnDefaultDisplay); + return SECONDARY_DISPLAY_MAPPING_FAILED; + } + mappingNeeded = true; + } + if (!mappingNeeded && mVisibleBackgroundUsersEnabled + && isProfile(userId, profileGroupId)) { + mappingNeeded = true; + } + + if (!mappingNeeded) { + // Don't need to do anything because methods (such as isUserVisible()) already + // know that the current user (and its profiles) is assigned to the default display. + // But on MUMD devices, profiles are only supported in the default display, so it + // cannot return yet as it needs to check if the parent is also assigned to the + // DEFAULT_DISPLAY (this is done indirectly below when it checks that the profile + // parent is the current user, as the current user is always assigned to the + // DEFAULT_DISPLAY). + if (DBG) { + Slogf.d(TAG, "ignoring mapping for default display for user %d starting as %s", + userId, userStartModeToString(userStartMode)); + } + return SECONDARY_DISPLAY_MAPPING_NOT_NEEDED; } - return SECONDARY_DISPLAY_MAPPING_NOT_NEEDED; } if (userId == UserHandle.USER_SYSTEM) { @@ -421,13 +457,14 @@ public final class UserVisibilityMediator implements Dumpable { return false; } - int userAssignedToDisplay = getUserAssignedToDisplay(displayId, - /* returnCurrentUserByDefault= */ false); + // First check if the user started on display + int userAssignedToDisplay = getUserStartedOnDisplay(displayId); if (userAssignedToDisplay != USER_NULL) { Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): failed because display was assigned" + " to user %d on start", userId, displayId, userAssignedToDisplay); return false; } + // Then if was assigned extra userAssignedToDisplay = mExtraDisplaysAssignedToUsers.get(userId, USER_NULL); if (userAssignedToDisplay != USER_NULL) { Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): failed because user %d was already " @@ -435,7 +472,8 @@ public final class UserVisibilityMediator implements Dumpable { return false; } if (DBG) { - Slogf.d(TAG, "addding %d -> %d to map", displayId, userId); + Slogf.d(TAG, "addding %d -> %d to mExtraDisplaysAssignedToUsers", displayId, + userId); } mExtraDisplaysAssignedToUsers.put(displayId, userId); } @@ -501,7 +539,7 @@ public final class UserVisibilityMediator implements Dumpable { mStartedProfileGroupIds.delete(userId); if (!mVisibleBackgroundUsersEnabled) { - // Don't need to do update mUsersOnSecondaryDisplays because methods (such as + // Don't need to update mUsersAssignedToDisplayOnStart because methods (such as // isUserVisible()) already know that the current user (and their profiles) is // assigned to the default display. return; @@ -536,11 +574,10 @@ public final class UserVisibilityMediator implements Dumpable { return true; } - // Device doesn't support multiple users on multiple displays, so only users checked above - // can be visible if (!mVisibleBackgroundUsersEnabled) { if (DBG) { - Slogf.d(TAG, "isUserVisible(%d): false for non-current user on MUMD", userId); + Slogf.d(TAG, "isUserVisible(%d): false for non-current user (or its profiles) when" + + " device doesn't support visible background users", userId); } return false; } @@ -559,15 +596,29 @@ public final class UserVisibilityMediator implements Dumpable { * See {@link UserManagerInternal#isUserVisible(int, int)}. */ public boolean isUserVisible(@UserIdInt int userId, int displayId) { - if (displayId == Display.INVALID_DISPLAY) { + if (displayId == INVALID_DISPLAY) { return false; } - if (!mVisibleBackgroundUsersEnabled || displayId == Display.DEFAULT_DISPLAY) { - // TODO(b/245939659): will need to move the displayId == Display.DEFAULT_DISPLAY outside - // once it supports background users on DEFAULT_DISPLAY (for example, passengers in a - // no-driver configuration) - return isCurrentUserOrRunningProfileOfCurrentUser(userId); + // Current user is always visible on: + // - Default display + // - Secondary displays when device doesn't support visible bg users + // - Or when explicitly added (which is checked below) + if (isCurrentUserOrRunningProfileOfCurrentUser(userId) + && (displayId == DEFAULT_DISPLAY || !mVisibleBackgroundUsersEnabled)) { + if (VERBOSE) { + Slogf.v(TAG, "isUserVisible(%d, %d): returning true for current user/profile", + userId, displayId); + } + return true; + } + + if (!mVisibleBackgroundUsersEnabled) { + if (DBG) { + Slogf.d(TAG, "isUserVisible(%d, %d): returning false as device does not support" + + " visible background users", userId, displayId); + } + return false; } synchronized (mLock) { @@ -575,7 +626,8 @@ public final class UserVisibilityMediator implements Dumpable { // User assigned to display on start return true; } - // Check for extra assignment + + // Check for extra display assignment return mExtraDisplaysAssignedToUsers.get(displayId, USER_NULL) == userId; } } @@ -585,15 +637,31 @@ public final class UserVisibilityMediator implements Dumpable { */ public int getDisplayAssignedToUser(@UserIdInt int userId) { if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) { - return Display.DEFAULT_DISPLAY; + if (mVisibleBackgroundUserOnDefaultDisplayAllowed) { + // When device supports visible bg users on default display, the default display is + // assigned to the current user, unless a user is started visible on it + int userStartedOnDefaultDisplay; + synchronized (mLock) { + userStartedOnDefaultDisplay = getUserStartedOnDisplay(DEFAULT_DISPLAY); + } + if (userStartedOnDefaultDisplay != USER_NULL) { + if (DBG) { + Slogf.d(TAG, "getDisplayAssignedToUser(%d): returning INVALID_DISPLAY for " + + "current user user %d was started on DEFAULT_DISPLAY", + userId, userStartedOnDefaultDisplay); + } + return INVALID_DISPLAY; + } + } + return DEFAULT_DISPLAY; } if (!mVisibleBackgroundUsersEnabled) { - return Display.INVALID_DISPLAY; + return INVALID_DISPLAY; } synchronized (mLock) { - return mUsersAssignedToDisplayOnStart.get(userId, Display.INVALID_DISPLAY); + return mUsersAssignedToDisplayOnStart.get(userId, INVALID_DISPLAY); } } @@ -604,6 +672,13 @@ public final class UserVisibilityMediator implements Dumpable { return getUserAssignedToDisplay(displayId, /* returnCurrentUserByDefault= */ true); } + /** + * Gets the user explicitly assigned to a display. + */ + private @UserIdInt int getUserStartedOnDisplay(@UserIdInt int displayId) { + return getUserAssignedToDisplay(displayId, /* returnCurrentUserByDefault= */ false); + } + /** * Gets the user explicitly assigned to a display, or the current user when no user is assigned * to it (and {@code returnCurrentUserByDefault} is {@code true}). @@ -611,7 +686,8 @@ public final class UserVisibilityMediator implements Dumpable { private @UserIdInt int getUserAssignedToDisplay(@UserIdInt int displayId, boolean returnCurrentUserByDefault) { if (returnCurrentUserByDefault - && (displayId == Display.DEFAULT_DISPLAY || !mVisibleBackgroundUsersEnabled)) { + && ((displayId == DEFAULT_DISPLAY && !mVisibleBackgroundUserOnDefaultDisplayAllowed + || !mVisibleBackgroundUsersEnabled))) { return getCurrentUserId(); } @@ -763,8 +839,10 @@ public final class UserVisibilityMediator implements Dumpable { ipw.print("Supports visible background users on displays: "); ipw.println(mVisibleBackgroundUsersEnabled); - dumpSparseIntArray(ipw, mUsersAssignedToDisplayOnStart, "user / display", "u", "d"); + ipw.print("Allows visible background users on default display: "); + ipw.println(mVisibleBackgroundUserOnDefaultDisplayAllowed); + dumpSparseIntArray(ipw, mUsersAssignedToDisplayOnStart, "user / display", "u", "d"); dumpSparseIntArray(ipw, mExtraDisplaysAssignedToUsers, "extra display / user", "d", "u"); @@ -872,4 +950,10 @@ public final class UserVisibilityMediator implements Dumpable { return mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID); } } + + private static String secondaryDisplayMappingStatusToString( + @SecondaryDisplayMappingStatus int status) { + return DebugUtils.constantToString(UserVisibilityMediator.class, + PREFIX_SECONDARY_DISPLAY_MAPPING, status); + } } diff --git a/services/tests/mockingservicestests/src/com/android/server/DumpableDumperRule.java b/services/tests/mockingservicestests/src/com/android/server/DumpableDumperRule.java index 33275bd471f60..a0687f6c1ba96 100644 --- a/services/tests/mockingservicestests/src/com/android/server/DumpableDumperRule.java +++ b/services/tests/mockingservicestests/src/com/android/server/DumpableDumperRule.java @@ -62,14 +62,21 @@ public final class DumpableDumperRule implements TestRule { }; } - private void dumpOnFailure(String testName) throws IOException { + /** + * Logs all dumpables. + */ + public void dump(String reason) { if (mDumpables.isEmpty()) { return; } - Log.w(TAG, "Dumping " + mDumpables.size() + " dumpables on failure of " + testName); + Log.w(TAG, "Dumping " + mDumpables.size() + " dumpable(s). Reason: " + reason); mDumpables.forEach(d -> logDumpable(d)); } + private void dumpOnFailure(String testName) throws IOException { + dump("failure of " + testName); + } + private void logDumpable(Dumpable dumpable) { try { try (StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw)) { diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUMDTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUMDTest.java index 579621ca86b59..36c9f2ec869b3 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUMDTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUMDTest.java @@ -15,6 +15,8 @@ */ package com.android.server.pm; +import org.junit.Test; + /** * Tests for {@link UserVisibilityMediator} tests for devices that support concurrent Multiple * Users on Multiple Displays (A.K.A {@code MUMD}). @@ -26,6 +28,19 @@ public final class UserVisibilityMediatorMUMDTest extends UserVisibilityMediatorVisibleBackgroundUserTestCase { public UserVisibilityMediatorMUMDTest() throws Exception { - super(/* usersOnSecondaryDisplaysEnabled= */ true); + super(/* backgroundUsersOnDisplaysEnabled= */ true, + /* backgroundUserOnDefaultDisplayAllowed= */ false); + } + + @Test + public void testStartVisibleBgUser_onDefaultDisplay() throws Exception { + int userId = visibleBgUserCannotBeStartedOnDefaultDisplayTest(); + + assertInvisibleUserCannotBeAssignedExtraDisplay(userId, SECONDARY_DISPLAY_ID); + } + + @Test + public void testStartBgUser_onDefaultDisplay_visible() throws Exception { + visibleBgUserCannotBeStartedOnDefaultDisplayTest(); } } diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java new file mode 100644 index 0000000000000..01ce696a1cbf6 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm; + +import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.Display.INVALID_DISPLAY; + +import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_FAILURE; +import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE; +import static com.android.server.pm.UserVisibilityChangedEvent.onInvisible; +import static com.android.server.pm.UserVisibilityChangedEvent.onVisible; +import static com.android.server.pm.UserVisibilityMediator.INITIAL_CURRENT_USER_ID; + +import org.junit.Test; + +/** + * Tests for {@link UserVisibilityMediator} tests for devices that support not only concurrent + * Multiple Users on Multiple Displays, but also let background users to be visible in the default + * display (A.K.A {@code MUPAND} - MUltiple Passengers, No Driver). + * + *
Run as {@code +* atest FrameworksMockingServicesTests:com.android.server.pm.UserVisibilityMediatorMUPANDTest} + */ +public final class UserVisibilityMediatorMUPANDTest + extends UserVisibilityMediatorVisibleBackgroundUserTestCase { + + public UserVisibilityMediatorMUPANDTest() throws Exception { + super(/* backgroundUsersOnDisplaysEnabled= */ true, + /* backgroundUserOnDefaultDisplayAllowed= */ true); + } + + @Test + public void testStartVisibleBgUser_onDefaultDisplay_initialCurrentUserId() + throws Exception { + int currentUserId = INITIAL_CURRENT_USER_ID; + int visibleBgUserId = USER_ID; + int otherUserId = OTHER_USER_ID; + + AsyncUserVisibilityListener listener = addListenerForEvents(onVisible(visibleBgUserId)); + + int result = mMediator.assignUserToDisplayOnStart(visibleBgUserId, visibleBgUserId, + BG_VISIBLE, DEFAULT_DISPLAY); + assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE); + expectVisibleUsers(currentUserId, visibleBgUserId); + + // Assert bg user visibility + expectUserIsVisible(visibleBgUserId); + expectUserIsVisibleOnDisplay(visibleBgUserId, DEFAULT_DISPLAY); + expectUserIsNotVisibleOnDisplay(visibleBgUserId, INVALID_DISPLAY); + expectDisplayAssignedToUser(visibleBgUserId, DEFAULT_DISPLAY); + expectUserAssignedToDisplay(DEFAULT_DISPLAY, visibleBgUserId); + + // Assert current user visibility + expectUserIsVisible(currentUserId); + expectUserIsVisibleOnDisplay(currentUserId, DEFAULT_DISPLAY); + expectUserIsNotVisibleOnDisplay(currentUserId, INVALID_DISPLAY); + expectDisplayAssignedToUser(currentUserId, INVALID_DISPLAY); + + assertUserCanBeAssignedExtraDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID); + + // Make sure another user cannot be started on default display + int result2 = mMediator.assignUserToDisplayOnStart(otherUserId, visibleBgUserId, + BG_VISIBLE, DEFAULT_DISPLAY); + assertStartUserResult(result2, USER_ASSIGNMENT_RESULT_FAILURE, + "when user (%d) is starting on default display after it was started by user %d", + otherUserId, visibleBgUserId); + expectVisibleUsers(currentUserId, visibleBgUserId); + + listener.verify(); + } + + @Test + public void testStartVisibleBgUser_onDefaultDisplay_nonInitialCurrentUserId() + throws Exception { + int currentUserId = OTHER_USER_ID; + int visibleBgUserId = USER_ID; + int otherUserId = YET_ANOTHER_USER_ID; + + AsyncUserVisibilityListener listener = addListenerForEvents( + onInvisible(INITIAL_CURRENT_USER_ID), + onVisible(currentUserId), + onVisible(visibleBgUserId)); + startForegroundUser(currentUserId); + + int result = mMediator.assignUserToDisplayOnStart(visibleBgUserId, visibleBgUserId, + BG_VISIBLE, DEFAULT_DISPLAY); + assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE); + expectVisibleUsers(currentUserId, visibleBgUserId); + + // Assert bg user visibility + expectUserIsVisible(visibleBgUserId); + expectUserIsVisibleOnDisplay(visibleBgUserId, DEFAULT_DISPLAY); + expectUserIsNotVisibleOnDisplay(visibleBgUserId, INVALID_DISPLAY); + expectDisplayAssignedToUser(visibleBgUserId, DEFAULT_DISPLAY); + expectUserAssignedToDisplay(DEFAULT_DISPLAY, visibleBgUserId); + + // Assert current user visibility + expectUserIsVisible(currentUserId); + expectUserIsVisibleOnDisplay(currentUserId, DEFAULT_DISPLAY); + expectUserIsNotVisibleOnDisplay(currentUserId, INVALID_DISPLAY); + expectDisplayAssignedToUser(currentUserId, INVALID_DISPLAY); + + assertUserCanBeAssignedExtraDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID); + + // Make sure another user cannot be started on default display + int result2 = mMediator.assignUserToDisplayOnStart(otherUserId, visibleBgUserId, + BG_VISIBLE, DEFAULT_DISPLAY); + assertStartUserResult(result2, USER_ASSIGNMENT_RESULT_FAILURE, + "when user (%d) is starting on default display after it was started by user %d", + otherUserId, visibleBgUserId); + expectVisibleUsers(currentUserId, visibleBgUserId); + + listener.verify(); + } +} diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorSUSDTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorSUSDTest.java index b9ba780ff685a..c195064071f65 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorSUSDTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorSUSDTest.java @@ -37,7 +37,15 @@ import org.junit.Test; public final class UserVisibilityMediatorSUSDTest extends UserVisibilityMediatorTestCase { public UserVisibilityMediatorSUSDTest() { - super(/* usersOnSecondaryDisplaysEnabled= */ false); + super(/* backgroundUsersOnDisplaysEnabled= */ false, + /* backgroundUserOnDefaultDisplayAllowed= */ false); + } + + @Test + public void testStartVisibleBgUser_onDefaultDisplay() throws Exception { + int userId = visibleBgUserCannotBeStartedOnDefaultDisplayTest(); + + assertInvisibleUserCannotBeAssignedExtraDisplay(userId, SECONDARY_DISPLAY_ID); } @Test @@ -100,6 +108,11 @@ public final class UserVisibilityMediatorSUSDTest extends UserVisibilityMediator listener.verify(); } + @Test + public void testStartBgUser_onDefaultDisplay_visible() throws Exception { + visibleBgUserCannotBeStartedOnDefaultDisplayTest(); + } + @Test public void testStartVisibleBgProfile_onDefaultDisplay_whenParentIsCurrentUser() throws Exception { diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java index c59834bea6cae..5176d684ace68 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java @@ -78,6 +78,11 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase { */ protected static final int OTHER_USER_ID = 666; + /** + * Id for yeat another simple user. + */ + protected static final int YET_ANOTHER_USER_ID = 700; + /** * Id for a user that has one profile (whose id is {@link #PROFILE_USER_ID}. * @@ -110,11 +115,14 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase { protected AsyncUserVisibilityListener.Factory mListenerFactory; private final boolean mBackgroundUsersOnDisplaysEnabled; + private final boolean mBackgroundUserOnDefaultDisplayAllowed; protected UserVisibilityMediator mMediator; - protected UserVisibilityMediatorTestCase(boolean backgroundUsersOnDisplaysEnabled) { + protected UserVisibilityMediatorTestCase(boolean backgroundUsersOnDisplaysEnabled, + boolean backgroundUserOnDefaultDisplayAllowed) { mBackgroundUsersOnDisplaysEnabled = backgroundUsersOnDisplaysEnabled; + mBackgroundUserOnDefaultDisplayAllowed = backgroundUserOnDefaultDisplayAllowed; } @Before @@ -123,7 +131,8 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase { Thread thread = mHandler.getLooper().getThread(); Log.i(TAG, "setFixtures(): using thread " + thread + " (from handler " + mHandler + ")"); mListenerFactory = new AsyncUserVisibilityListener.Factory(mExpect, thread); - mMediator = new UserVisibilityMediator(mBackgroundUsersOnDisplaysEnabled, mHandler); + mMediator = new UserVisibilityMediator(mBackgroundUsersOnDisplaysEnabled, + mBackgroundUserOnDefaultDisplayAllowed, mHandler); mDumpableDumperRule.addDumpable(mMediator); } @@ -170,14 +179,8 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase { listener.verify(); } - @Test - public final void testStartVisibleBgUser_onDefaultDisplay() throws Exception { - visibleBgUserCannotBeStartedOnDefaultDisplayTest(); - - assertInvisibleUserCannotBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID); - } - - protected final void visibleBgUserCannotBeStartedOnDefaultDisplayTest() throws Exception { + protected final @UserIdInt int visibleBgUserCannotBeStartedOnDefaultDisplayTest() + throws Exception { AsyncUserVisibilityListener listener = addListenerForNoEvents(); int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, BG_VISIBLE, @@ -188,6 +191,8 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase { expectNoDisplayAssignedToUser(USER_ID); listener.verify(); + + return USER_ID; } @Test @@ -504,7 +509,14 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase { } protected void assertStartUserResult(int actualResult, int expectedResult) { - assertWithMessage("startUser() result (where %s=%s and %s=%s)", + assertStartUserResult(actualResult, expectedResult, ""); + } + + @SuppressWarnings("AnnotateFormatMethod") + protected void assertStartUserResult(int actualResult, int expectedResult, + String extraMessageFormat, Object... extraMessageArguments) { + String extraMessage = String.format(extraMessageFormat, extraMessageArguments); + assertWithMessage("startUser() result %s(where %s=%s and %s=%s)", extraMessage, expectedResult, userAssignmentResultToString(expectedResult), actualResult, userAssignmentResultToString(actualResult)) .that(actualResult).isEqualTo(expectedResult); diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java index 627553bcfa185..49c6a8854c49a 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java @@ -38,9 +38,9 @@ import org.junit.Test; abstract class UserVisibilityMediatorVisibleBackgroundUserTestCase extends UserVisibilityMediatorTestCase { - UserVisibilityMediatorVisibleBackgroundUserTestCase(boolean backgroundUsersOnDisplaysEnabled) - throws Exception { - super(backgroundUsersOnDisplaysEnabled); + UserVisibilityMediatorVisibleBackgroundUserTestCase(boolean backgroundUsersOnDisplaysEnabled, + boolean backgroundUserOnDefaultDisplayAllowed) throws Exception { + super(backgroundUsersOnDisplaysEnabled, backgroundUserOnDefaultDisplayAllowed); } @Test