Merge "Fixed UserVisibilityMediator profile scenario."
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java
index 3c5f309..eb3be54 100644
--- a/services/core/java/com/android/server/pm/UserManagerInternal.java
+++ b/services/core/java/com/android/server/pm/UserManagerInternal.java
@@ -62,12 +62,11 @@
})
public @interface UserAssignmentResult {}
- // TODO(b/248408342): Move keep annotation to the method referencing these fields reflectively.
- @Keep public static final int USER_START_MODE_FOREGROUND = 1;
- @Keep public static final int USER_START_MODE_BACKGROUND = 2;
- @Keep public static final int USER_START_MODE_BACKGROUND_VISIBLE = 3;
-
private static final String PREFIX_USER_START_MODE = "USER_START_MODE_";
+
+ /**
+ * Type used to indicate how a user started.
+ */
@IntDef(flag = false, prefix = {PREFIX_USER_START_MODE}, value = {
USER_START_MODE_FOREGROUND,
USER_START_MODE_BACKGROUND,
@@ -75,6 +74,32 @@
})
public @interface UserStartMode {}
+ // TODO(b/248408342): Move keep annotations below to the method referencing these fields
+ // reflectively.
+
+ /** (Full) user started on foreground (a.k.a. "current user"). */
+ @Keep public static final int USER_START_MODE_FOREGROUND = 1;
+
+ /**
+ * User (full or profile) started on background and is
+ * {@link UserManager#isUserVisible() invisible}.
+ *
+ * <p>This is the "traditional" way of starting a background user, and can be used to start
+ * profiles as well, although starting an invisible profile is not common from the System UI
+ * (it could be done through APIs or adb, though).
+ */
+ @Keep public static final int USER_START_MODE_BACKGROUND = 2;
+
+ /**
+ * User (full or profile) started on background and is
+ * {@link UserManager#isUserVisible() visible}.
+ *
+ * <p>This is the "traditional" way of starting a profile (i.e., when the profile of the current
+ * user is the current foreground user), but it can also be used to start a full user associated
+ * with a display (which is the case on automotives with passenger displays).
+ */
+ @Keep public static final int USER_START_MODE_BACKGROUND_VISIBLE = 3;
+
public interface UserRestrictionsListener {
/**
* Called when a user restriction changes.
diff --git a/services/core/java/com/android/server/pm/UserVisibilityMediator.java b/services/core/java/com/android/server/pm/UserVisibilityMediator.java
index 1f935f90..0a181a4 100644
--- a/services/core/java/com/android/server/pm/UserVisibilityMediator.java
+++ b/services/core/java/com/android/server/pm/UserVisibilityMediator.java
@@ -41,6 +41,7 @@
import android.util.EventLog;
import android.util.IndentingPrintWriter;
import android.util.IntArray;
+import android.util.Log;
import android.util.SparseIntArray;
import android.view.Display;
@@ -54,6 +55,8 @@
import com.android.server.utils.Slogf;
import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
@@ -76,11 +79,11 @@
*/
public final class UserVisibilityMediator implements Dumpable {
- private static final boolean DBG = false; // DO NOT SUBMIT WITH TRUE
- private static final boolean VERBOSE = false; // DO NOT SUBMIT WITH TRUE
-
private static final String TAG = UserVisibilityMediator.class.getSimpleName();
+ private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final boolean VERBOSE = false; // DO NOT SUBMIT WITH TRUE
+
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;
@@ -97,7 +100,7 @@
})
public @interface SecondaryDisplayMappingStatus {}
- // TODO(b/242195409): might need to change this if boot logic is refactored for HSUM devices
+ // TODO(b/266158156): might need to change this if boot logic is refactored for HSUM devices
@VisibleForTesting
static final int INITIAL_CURRENT_USER_ID = USER_SYSTEM;
@@ -131,10 +134,23 @@
private final SparseIntArray mExtraDisplaysAssignedToUsers;
/**
- * Mapping from each started user to its profile group.
+ * Mapping of each user that started visible (key) to its profile group id (value).
+ *
+ * <p>It's used to determine not just if the user is visible, but also
+ * {@link #isProfile(int, int) if it's a profile}.
*/
@GuardedBy("mLock")
- private final SparseIntArray mStartedProfileGroupIds = new SparseIntArray();
+ private final SparseIntArray mStartedVisibleProfileGroupIds = new SparseIntArray();
+
+ /**
+ * List of profiles that have explicitly started invisible.
+ *
+ * <p>Only used for debugging purposes (and set when {@link #DBG} is {@code true}), hence we
+ * don't care about autoboxing.
+ */
+ @GuardedBy("mLock")
+ @Nullable
+ private final List<Integer> mStartedInvisibleProfileUserIds;
/**
* Handler user to call listeners
@@ -164,9 +180,14 @@
mUsersAssignedToDisplayOnStart = null;
mExtraDisplaysAssignedToUsers = null;
}
+ mStartedInvisibleProfileUserIds = DBG ? new ArrayList<>(4) : null;
mHandler = handler;
- // TODO(b/242195409): might need to change this if boot logic is refactored for HSUM devices
- mStartedProfileGroupIds.put(INITIAL_CURRENT_USER_ID, INITIAL_CURRENT_USER_ID);
+ // TODO(b/266158156): might need to change this if boot logic is refactored for HSUM devices
+ mStartedVisibleProfileGroupIds.put(INITIAL_CURRENT_USER_ID, INITIAL_CURRENT_USER_ID);
+
+ if (DBG) {
+ Slogf.i(TAG, "UserVisibilityMediator created with DBG on");
+ }
}
/**
@@ -177,6 +198,8 @@
int displayId) {
Preconditions.checkArgument(!isSpecialUserId(userId), "user id cannot be generic: %d",
userId);
+ validateUserStartMode(userStartMode);
+
// This method needs to perform 4 actions:
//
// 1. Check if the user can be started given the provided arguments
@@ -223,14 +246,29 @@
visibleUsersBefore = getVisibleUsers();
- // Set current user / profiles state
- if (userStartMode == USER_START_MODE_FOREGROUND) {
- mCurrentUserId = userId;
+ // Set current user / started users state
+ switch (userStartMode) {
+ case USER_START_MODE_FOREGROUND:
+ mCurrentUserId = userId;
+ // Fallthrough
+ case USER_START_MODE_BACKGROUND_VISIBLE:
+ if (DBG) {
+ Slogf.d(TAG, "adding visible user / profile group id mapping (%d -> %d)",
+ userId, profileGroupId);
+ }
+ mStartedVisibleProfileGroupIds.put(userId, profileGroupId);
+ break;
+ case USER_START_MODE_BACKGROUND:
+ if (mStartedInvisibleProfileUserIds != null
+ && isProfile(userId, profileGroupId)) {
+ Slogf.d(TAG, "adding user %d to list of invisible profiles", userId);
+ mStartedInvisibleProfileUserIds.add(userId);
+ }
+ break;
+ default:
+ Slogf.wtf(TAG, "invalid userStartMode passed to assignUserToDisplayOnStart: "
+ + "%d", userStartMode);
}
- if (DBG) {
- Slogf.d(TAG, "adding user / profile mapping (%d -> %d)", userId, profileGroupId);
- }
- mStartedProfileGroupIds.put(userId, profileGroupId);
// Set user / display state
switch (mappingResult) {
@@ -288,39 +326,46 @@
boolean foreground = userStartMode == USER_START_MODE_FOREGROUND;
if (displayId != DEFAULT_DISPLAY) {
if (foreground) {
- Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %b, %d) failed: cannot start "
+ Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %s, %d) failed: cannot start "
+ "foreground user on secondary display", userId, profileGroupId,
- foreground, displayId);
+ userStartModeToString(userStartMode), displayId);
return USER_ASSIGNMENT_RESULT_FAILURE;
}
if (!mVisibleBackgroundUsersEnabled) {
- Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %b, %d) failed: called on "
+ Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %s, %d) failed: called on "
+ "device that doesn't support multiple users on multiple displays",
- userId, profileGroupId, foreground, displayId);
+ userId, profileGroupId, userStartModeToString(userStartMode), displayId);
return USER_ASSIGNMENT_RESULT_FAILURE;
}
}
if (isProfile(userId, profileGroupId)) {
if (displayId != DEFAULT_DISPLAY) {
- Slogf.w(TAG, "canStartUserLocked(%d, %d, %b, %d) failed: cannot start profile user "
- + "on secondary display", userId, profileGroupId, foreground,
- displayId);
+ Slogf.w(TAG, "canStartUserLocked(%d, %d, %s, %d) failed: cannot start profile user "
+ + "on secondary display", userId, profileGroupId,
+ userStartModeToString(userStartMode), displayId);
return USER_ASSIGNMENT_RESULT_FAILURE;
}
- if (foreground) {
- Slogf.w(TAG, "startUser(%d, %d, %b, %d) failed: cannot start profile user in "
- + "foreground", userId, profileGroupId, foreground, displayId);
- return USER_ASSIGNMENT_RESULT_FAILURE;
- } else {
- boolean isParentVisibleOnDisplay = isUserVisible(profileGroupId, displayId);
- if (DBG) {
- Slogf.d(TAG, "parent visible on display: %b", isParentVisibleOnDisplay);
- }
- return isParentVisibleOnDisplay
- ? USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE
- : USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE;
+ switch (userStartMode) {
+ case USER_START_MODE_FOREGROUND:
+ Slogf.w(TAG, "startUser(%d, %d, %s, %d) failed: cannot start profile user in "
+ + "foreground", userId, profileGroupId,
+ userStartModeToString(userStartMode), displayId);
+ return USER_ASSIGNMENT_RESULT_FAILURE;
+ case USER_START_MODE_BACKGROUND_VISIBLE:
+ boolean isParentVisibleOnDisplay = isUserVisible(profileGroupId, displayId);
+ if (!isParentVisibleOnDisplay) {
+ Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %s, %d) failed: cannot"
+ + " start profile user visible when its parent is not visible in "
+ + "that display", userId, profileGroupId,
+ userStartModeToString(userStartMode), displayId);
+ return USER_ASSIGNMENT_RESULT_FAILURE;
+ }
+ return USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE;
+ case USER_START_MODE_BACKGROUND:
+ return USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE;
}
+
}
return foreground || displayId != DEFAULT_DISPLAY
@@ -338,8 +383,9 @@
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"
+ if (userStartedOnDefaultDisplay != USER_NULL
+ && userStartedOnDefaultDisplay != profileGroupId) {
+ Slogf.w(TAG, "canAssignUserToDisplayLocked(): cannot start user %d visible on"
+ " default display because user %d already did so", userId,
userStartedOnDefaultDisplay);
return SECONDARY_DISPLAY_MAPPING_FAILED;
@@ -445,7 +491,7 @@
userId, displayId);
return false;
}
- if (isStartedProfile(userId)) {
+ if (isStartedVisibleProfileLocked(userId)) {
Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): failed because user is a profile",
userId, displayId);
return false;
@@ -533,10 +579,14 @@
@GuardedBy("mLock")
private void unassignUserFromAllDisplaysOnStopLocked(@UserIdInt int userId) {
if (DBG) {
- Slogf.d(TAG, "Removing %d from mStartedProfileGroupIds (%s)", userId,
- mStartedProfileGroupIds);
+ Slogf.d(TAG, "Removing %d from mStartedVisibleProfileGroupIds (%s)", userId,
+ mStartedVisibleProfileGroupIds);
}
- mStartedProfileGroupIds.delete(userId);
+ mStartedVisibleProfileGroupIds.delete(userId);
+ if (mStartedInvisibleProfileUserIds != null) {
+ Slogf.d(TAG, "Removing %d from list of invisible profiles", userId);
+ mStartedInvisibleProfileUserIds.remove(Integer.valueOf(userId));
+ }
if (!mVisibleBackgroundUsersEnabled) {
// Don't need to update mUsersAssignedToDisplayOnStart because methods (such as
@@ -566,7 +616,8 @@
* See {@link UserManagerInternal#isUserVisible(int)}.
*/
public boolean isUserVisible(@UserIdInt int userId) {
- // First check current foreground user and their profiles (on main display)
+ // For optimization (as most devices don't support visible background users), check for
+ // current foreground user and their profiles first
if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) {
if (VERBOSE) {
Slogf.v(TAG, "isUserVisible(%d): true to current user or profile", userId);
@@ -575,19 +626,31 @@
}
if (!mVisibleBackgroundUsersEnabled) {
- if (DBG) {
- Slogf.d(TAG, "isUserVisible(%d): false for non-current user (or its profiles) when"
+ if (VERBOSE) {
+ Slogf.v(TAG, "isUserVisible(%d): false for non-current user (or its profiles) when"
+ " device doesn't support visible background users", userId);
}
return false;
}
- boolean visible;
+
synchronized (mLock) {
- visible = mUsersAssignedToDisplayOnStart.indexOfKey(userId) >= 0;
+ int profileGroupId;
+ synchronized (mLock) {
+ profileGroupId = mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID);
+ }
+ if (isProfile(userId, profileGroupId)) {
+ return isUserAssignedToDisplayOnStartLocked(profileGroupId);
+ }
+ return isUserAssignedToDisplayOnStartLocked(userId);
}
- if (DBG) {
- Slogf.d(TAG, "isUserVisible(%d): %b from mapping", userId, visible);
+ }
+
+ @GuardedBy("mLock")
+ private boolean isUserAssignedToDisplayOnStartLocked(@UserIdInt int userId) {
+ boolean visible = mUsersAssignedToDisplayOnStart.indexOfKey(userId) >= 0;
+ if (VERBOSE) {
+ Slogf.v(TAG, "isUserAssignedToDisplayOnStartLocked(%d): %b", userId, visible);
}
return visible;
}
@@ -600,7 +663,8 @@
return false;
}
- // Current user is always visible on:
+ // For optimization (as most devices don't support visible background users), check for
+ // current user and profile first. 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)
@@ -622,16 +686,28 @@
}
synchronized (mLock) {
- if (mUsersAssignedToDisplayOnStart.get(userId, Display.INVALID_DISPLAY) == displayId) {
- // User assigned to display on start
- return true;
+ int profileGroupId;
+ synchronized (mLock) {
+ profileGroupId = mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID);
}
-
- // Check for extra display assignment
- return mExtraDisplaysAssignedToUsers.get(displayId, USER_NULL) == userId;
+ if (isProfile(userId, profileGroupId)) {
+ return isFullUserVisibleOnBackgroundLocked(profileGroupId, displayId);
+ }
+ return isFullUserVisibleOnBackgroundLocked(userId, displayId);
}
}
+ // NOTE: it doesn't check if the userId is a full user, it's up to the caller to check that
+ @GuardedBy("mLock")
+ private boolean isFullUserVisibleOnBackgroundLocked(@UserIdInt int userId, int displayId) {
+ if (mUsersAssignedToDisplayOnStart.get(userId, Display.INVALID_DISPLAY) == displayId) {
+ // User assigned to display on start
+ return true;
+ }
+ // Check for extra display assignment
+ return mExtraDisplaysAssignedToUsers.get(displayId, USER_NULL) == userId;
+ }
+
/**
* See {@link UserManagerInternal#getDisplayAssignedToUser(int)}.
*/
@@ -697,7 +773,7 @@
continue;
}
int userId = mUsersAssignedToDisplayOnStart.keyAt(i);
- if (!isStartedProfile(userId)) {
+ if (!isStartedVisibleProfileLocked(userId)) {
return userId;
} else if (DBG) {
Slogf.d(TAG, "getUserAssignedToDisplay(%d): skipping user %d because it's "
@@ -730,8 +806,8 @@
// number of users is too small, the gain is probably not worth the increase on complexity.
IntArray visibleUsers = new IntArray();
synchronized (mLock) {
- for (int i = 0; i < mStartedProfileGroupIds.size(); i++) {
- int userId = mStartedProfileGroupIds.keyAt(i);
+ for (int i = 0; i < mStartedVisibleProfileGroupIds.size(); i++) {
+ int userId = mStartedVisibleProfileGroupIds.keyAt(i);
if (isUserVisible(userId)) {
visibleUsers.add(userId);
}
@@ -764,7 +840,7 @@
}
}
- // TODO(b/242195409): remove this method if not needed anymore
+ // TODO(b/266158156): remove this method if not needed anymore
/**
* Nofify all listeners that the system user visibility changed.
*/
@@ -826,6 +902,9 @@
ipw.println("UserVisibilityMediator");
ipw.increaseIndent();
+ ipw.print("DBG: ");
+ ipw.println(DBG);
+
synchronized (mLock) {
ipw.print("Current user id: ");
ipw.println(mCurrentUserId);
@@ -833,8 +912,12 @@
ipw.print("Visible users: ");
ipw.println(getVisibleUsers());
- dumpSparseIntArray(ipw, mStartedProfileGroupIds, "started user / profile group",
- "u", "pg");
+ dumpSparseIntArray(ipw, mStartedVisibleProfileGroupIds,
+ "started visible user / profile group", "u", "pg");
+ if (mStartedInvisibleProfileUserIds != null) {
+ ipw.print("Profiles started invisible: ");
+ ipw.println(mStartedInvisibleProfileUserIds);
+ }
ipw.print("Supports visible background users on displays: ");
ipw.println(mVisibleBackgroundUsersEnabled);
@@ -933,22 +1016,25 @@
if (mCurrentUserId == userId) {
return true;
}
- return mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID) == mCurrentUserId;
+ return mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID)
+ == mCurrentUserId;
}
}
- private boolean isStartedProfile(@UserIdInt int userId) {
- int profileGroupId;
- synchronized (mLock) {
- profileGroupId = mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID);
- }
+ @GuardedBy("mLock")
+ private boolean isStartedVisibleProfileLocked(@UserIdInt int userId) {
+ int profileGroupId = mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID);
return isProfile(userId, profileGroupId);
}
- private @UserIdInt int getStartedProfileGroupId(@UserIdInt int userId) {
- synchronized (mLock) {
- return mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID);
+ private void validateUserStartMode(@UserStartMode int userStartMode) {
+ switch (userStartMode) {
+ case USER_START_MODE_FOREGROUND:
+ case USER_START_MODE_BACKGROUND:
+ case USER_START_MODE_BACKGROUND_VISIBLE:
+ return;
}
+ throw new IllegalArgumentException("Invalid user start mode: " + userStartMode);
}
private static String secondaryDisplayMappingStatusToString(
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java
index 01ce696..f69054b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java
@@ -20,6 +20,7 @@
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_INVISIBLE;
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;
@@ -73,8 +74,8 @@
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);
+ int result2 = mMediator.assignUserToDisplayOnStart(otherUserId, otherUserId, 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);
@@ -117,8 +118,8 @@
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);
+ int result2 = mMediator.assignUserToDisplayOnStart(otherUserId, otherUserId, 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);
@@ -126,4 +127,60 @@
listener.verify();
}
+
+ @Test
+ public void testStartVisibleBgProfile_onDefaultDisplay_whenParentIsStartedVisibleOnBg()
+ throws Exception {
+ AsyncUserVisibilityListener listener = addListenerForEvents(
+ onVisible(PARENT_USER_ID),
+ onVisible(PROFILE_USER_ID));
+ startUserInSecondaryDisplay(PARENT_USER_ID, DEFAULT_DISPLAY);
+
+ int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
+ BG_VISIBLE, DEFAULT_DISPLAY);
+ assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
+
+ // Assert parent user visibility
+ expectUserIsVisible(PARENT_USER_ID);
+ expectUserIsVisibleOnDisplay(PARENT_USER_ID, DEFAULT_DISPLAY);
+ expectUserIsNotVisibleOnDisplay(PARENT_USER_ID, INVALID_DISPLAY);
+ expectDisplayAssignedToUser(PARENT_USER_ID, DEFAULT_DISPLAY);
+ expectUserAssignedToDisplay(DEFAULT_DISPLAY, PARENT_USER_ID);
+ assertUserCanBeAssignedExtraDisplay(PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID);
+
+ // Assert profile user visibility
+ expectUserIsVisible(PROFILE_USER_ID);
+ expectUserIsVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY);
+ expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, INVALID_DISPLAY);
+ // Only full user (parent) is assigned to the display
+ expectDisplayAssignedToUser(PROFILE_USER_ID, INVALID_DISPLAY);
+ assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, OTHER_SECONDARY_DISPLAY_ID);
+
+ listener.verify();
+ }
+
+ @Test
+ public void testStartBgProfile_onDefaultDisplay_whenParentIsStartedVisibleOnBg()
+ throws Exception {
+ AsyncUserVisibilityListener listener = addListenerForEvents(onVisible(PARENT_USER_ID));
+ startUserInSecondaryDisplay(PARENT_USER_ID, DEFAULT_DISPLAY);
+
+ int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG,
+ DEFAULT_DISPLAY);
+ assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE);
+
+ // Assert parent user visibility
+ expectUserIsVisible(PARENT_USER_ID);
+ expectUserIsVisibleOnDisplay(PARENT_USER_ID, DEFAULT_DISPLAY);
+ expectUserIsNotVisibleOnDisplay(PARENT_USER_ID, INVALID_DISPLAY);
+ expectDisplayAssignedToUser(PARENT_USER_ID, DEFAULT_DISPLAY);
+ expectUserAssignedToDisplay(DEFAULT_DISPLAY, PARENT_USER_ID);
+ assertUserCanBeAssignedExtraDisplay(PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID);
+
+ // Assert profile user visibility
+ expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
+ expectNoDisplayAssignedToUser(PROFILE_USER_ID);
+ assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, OTHER_SECONDARY_DISPLAY_ID);
+ listener.verify();
+ }
}
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 5176d68..566084a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java
@@ -44,7 +44,6 @@
import android.util.IntArray;
import android.util.Log;
-import com.android.internal.util.Preconditions;
import com.android.server.ExtendedMockitoTestCase;
import org.junit.Before;
@@ -149,6 +148,12 @@
}
@Test
+ public final void testAssignUserToDisplayOnStart_invalidUserStartMode() {
+ assertThrows(IllegalArgumentException.class, () -> mMediator
+ .assignUserToDisplayOnStart(USER_ID, USER_ID, 666, DEFAULT_DISPLAY));
+ }
+
+ @Test
public final void testStartFgUser_onSecondaryDisplay() throws Exception {
AsyncUserVisibilityListener listener = addListenerForNoEvents();
@@ -283,7 +288,7 @@
int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
BG_VISIBLE, DEFAULT_DISPLAY);
- assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE);
+ assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
@@ -299,14 +304,14 @@
int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
BG_VISIBLE, DEFAULT_DISPLAY);
- assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE);
+ assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY);
- assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+ assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
listener.verify();
}
@@ -332,6 +337,41 @@
}
@Test
+ public final void testStartBgProfile_onDefaultDisplay_whenParentIsNotStarted()
+ throws Exception {
+ AsyncUserVisibilityListener listener = addListenerForNoEvents();
+
+ int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG,
+ DEFAULT_DISPLAY);
+ assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE);
+
+ expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
+ expectNoDisplayAssignedToUser(PROFILE_USER_ID);
+
+ listener.verify();
+ }
+
+ @Test
+ public final void testStartBgProfile_onDefaultDisplay_whenParentIsStartedOnBg()
+ throws Exception {
+ AsyncUserVisibilityListener listener = addListenerForNoEvents();
+ startBackgroundUser(PARENT_USER_ID);
+
+ int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG,
+ DEFAULT_DISPLAY);
+ assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE);
+
+ expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
+
+ expectNoDisplayAssignedToUser(PROFILE_USER_ID);
+ expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY);
+
+ assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+
+ listener.verify();
+ }
+
+ @Test
public final void testStartBgProfile_onSecondaryDisplay() throws Exception {
AsyncUserVisibilityListener listener = addListenerForNoEvents();
@@ -485,8 +525,6 @@
* se.
*/
protected final void startUserInSecondaryDisplay(@UserIdInt int userId, int displayId) {
- Preconditions.checkArgument(displayId != INVALID_DISPLAY && displayId != DEFAULT_DISPLAY,
- "must pass a secondary display, not %d", displayId);
Log.d(TAG, "startUserInSecondaryDisplay(" + userId + ", " + displayId + ")");
int result = mMediator.assignUserToDisplayOnStart(userId, userId, BG_VISIBLE, displayId);
if (result != USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE) {
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 49c6a88..f084063 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java
@@ -108,34 +108,6 @@
}
@Test
- public final void testStartVisibleBgProfile_onDefaultDisplay_whenParentIsCurrentUser()
- throws Exception {
- AsyncUserVisibilityListener listener = addListenerForEvents(
- onInvisible(INITIAL_CURRENT_USER_ID),
- onVisible(PARENT_USER_ID),
- onVisible(PROFILE_USER_ID));
- startForegroundUser(PARENT_USER_ID);
-
- int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
- BG_VISIBLE, DEFAULT_DISPLAY);
- assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
- expectUserCannotBeUnassignedFromDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY);
-
- expectUserIsVisible(PROFILE_USER_ID);
- expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, INVALID_DISPLAY);
- expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
- expectUserIsVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY);
- expectVisibleUsers(PARENT_USER_ID, PROFILE_USER_ID);
-
- expectDisplayAssignedToUser(PROFILE_USER_ID, DEFAULT_DISPLAY);
- expectUserAssignedToDisplay(DEFAULT_DISPLAY, PARENT_USER_ID);
-
- assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
-
- listener.verify();
- }
-
- @Test
public final void testStartFgUser_onInvalidDisplay() throws Exception {
AsyncUserVisibilityListener listener = addListenerForNoEvents();
@@ -268,14 +240,83 @@
}
@Test
+ public final void testStartVisibleBgProfile_onDefaultDisplay_whenParentIsCurrentUser()
+ throws Exception {
+ AsyncUserVisibilityListener listener = addListenerForEvents(
+ onInvisible(INITIAL_CURRENT_USER_ID),
+ onVisible(PARENT_USER_ID),
+ onVisible(PROFILE_USER_ID));
+ startForegroundUser(PARENT_USER_ID);
+
+ int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
+ BG_VISIBLE, DEFAULT_DISPLAY);
+ assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
+ expectUserCannotBeUnassignedFromDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY);
+
+ expectUserIsVisible(PROFILE_USER_ID);
+ expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, INVALID_DISPLAY);
+ expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+ expectUserIsVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY);
+ expectVisibleUsers(PARENT_USER_ID, PROFILE_USER_ID);
+
+ expectDisplayAssignedToUser(PROFILE_USER_ID, DEFAULT_DISPLAY);
+ expectUserAssignedToDisplay(DEFAULT_DISPLAY, PARENT_USER_ID);
+
+ assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+
+ listener.verify();
+ }
+
+ @Test
public final void
- testStartVisibleBgProfile_onDefaultDisplay_whenParentVisibleOnSecondaryDisplay()
- throws Exception {
+ testStartVisibleBgProfile_onDefaultDisplay_whenParentIsStartedVisibleOnAnotherDisplay()
+ throws Exception {
AsyncUserVisibilityListener listener = addListenerForEvents(onVisible(PARENT_USER_ID));
startUserInSecondaryDisplay(PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID);
int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
BG_VISIBLE, DEFAULT_DISPLAY);
+ assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
+
+ expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
+ expectNoDisplayAssignedToUser(PROFILE_USER_ID);
+ expectUserAssignedToDisplay(OTHER_SECONDARY_DISPLAY_ID, PARENT_USER_ID);
+
+ assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+
+ listener.verify();
+ }
+
+ // Not supported - profiles can only be started on default display
+ @Test
+ public final void
+ testStartVisibleBgProfile_onSecondaryDisplay_whenParentIsStartedVisibleOnThatDisplay()
+ throws Exception {
+ AsyncUserVisibilityListener listener = addListenerForEvents(onVisible(PARENT_USER_ID));
+ startUserInSecondaryDisplay(PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID);
+
+ int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
+ BG_VISIBLE, DEFAULT_DISPLAY);
+ assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
+
+ expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
+ expectNoDisplayAssignedToUser(PROFILE_USER_ID);
+ expectUserAssignedToDisplay(OTHER_SECONDARY_DISPLAY_ID, PARENT_USER_ID);
+
+ assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+
+ listener.verify();
+ }
+
+ @Test
+ public final void
+ testStartProfile_onDefaultDisplay_whenParentIsStartedVisibleOnSecondaryDisplay()
+ throws Exception {
+ AsyncUserVisibilityListener listener = addListenerForEvents(onVisible(PARENT_USER_ID));
+ startUserInSecondaryDisplay(PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID);
+
+ int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG,
+ DEFAULT_DISPLAY);
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE);
expectUserIsNotVisibleAtAll(PROFILE_USER_ID);