Merge "New UserManagerInternal APIs for extra user / display assignment."

This commit is contained in:
Felipe Leme
2023-01-11 17:05:27 +00:00
committed by Android (Google) Code Review
6 changed files with 369 additions and 35 deletions

View File

@@ -388,8 +388,8 @@ public abstract class UserManagerInternal {
* and the user is {@link UserManager#isUserVisible() visible}.
*
* <p><b>NOTE: </b>this method is meant to be used only by {@code UserController} (when a user
* is started). If other clients (like {@code CarService} need to explicitly change the user /
* display assignment, we'll need to provide other APIs.
* is started); for extra unassignments, callers should call {@link
* #assignUserToExtraDisplay(int, int)} instead.
*
* <p><b>NOTE: </b>this method doesn't validate if the display exists, it's up to the caller to
* pass a valid display id.
@@ -397,15 +397,43 @@ public abstract class UserManagerInternal {
public abstract @UserAssignmentResult int assignUserToDisplayOnStart(@UserIdInt int userId,
@UserIdInt int profileGroupId, @UserStartMode int userStartMode, int displayId);
/**
* Assigns an extra display to the given user, so the user is visible on that display.
*
* <p>This method is meant to be used on automotive builds where a passenger zone has more than
* one display (for example, the "main" display and a smaller display used for input).
*
* <p><b>NOTE: </b>this call will be ignored on devices that do not
* {@link UserManager#isVisibleBackgroundUsersSupported() support visible background users}.
*
* @return whether the operation succeeded, in which case the user would be visible on the
* display.
*/
public abstract boolean assignUserToExtraDisplay(@UserIdInt int userId, int displayId);
/**
* Unassigns a user from its current display when it's stopping.
*
* <p><b>NOTE: </b>this method is meant to be used only by {@code UserController} (when a user
* is stopped). If other clients (like {@code CarService} need to explicitly change the user /
* display assignment, we'll need to provide other APIs.
* is stopped); for extra unassignments, callers should call
* {@link #unassignUserFromExtraDisplay(int, int)} instead.
*/
public abstract void unassignUserFromDisplayOnStop(@UserIdInt int userId);
/**
* Unassigns the extra display from the given user.
*
* <p>This method is meant to be used on automotive builds where a passenger zone has more than
* one display (for example, the "main" display and a smaller display used for input).
*
* <p><b>NOTE: </b>this call will be ignored on devices that do not
* {@link UserManager#isVisibleBackgroundUsersSupported() support visible background users}.
*
* @return whether the operation succeeded, i.e., the user was previously
* {@link #assignUserToExtraDisplay(int, int) assigned to an extra display}.
*/
public abstract boolean unassignUserFromExtraDisplay(@UserIdInt int userId, int displayId);
/**
* Returns {@code true} if the user is visible (as defined by
* {@link UserManager#isUserVisible()}.

View File

@@ -7037,6 +7037,16 @@ public class UserManagerService extends IUserManager.Stub {
userStartMode, displayId);
}
@Override
public boolean assignUserToExtraDisplay(int userId, int displayId) {
return mUserVisibilityMediator.assignUserToExtraDisplay(userId, displayId);
}
@Override
public boolean unassignUserFromExtraDisplay(int userId, int displayId) {
return mUserVisibilityMediator.unassignUserFromExtraDisplay(userId, displayId);
}
@Override
public void unassignUserFromDisplayOnStop(@UserIdInt int userId) {
mUserVisibilityMediator.unassignUserFromDisplayOnStop(userId);

View File

@@ -19,6 +19,7 @@ import static android.content.pm.UserInfo.NO_PROFILE_GROUP_ID;
import static android.os.UserHandle.USER_NULL;
import static android.os.UserHandle.USER_SYSTEM;
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_INVISIBLE;
@@ -113,7 +114,18 @@ public final class UserVisibilityMediator implements Dumpable {
*/
@Nullable
@GuardedBy("mLock")
private final SparseIntArray mUsersOnDisplaysMap;
private final SparseIntArray mUsersAssignedToDisplayOnStart;
/**
* Map of extra (i.e., not assigned on start, but by explicit calls to
* {@link #assignUserToExtraDisplay(int, int)}) displays assigned to user (key is display id,
* value is user id).
*
* <p>Only set when {@code mUsersOnSecondaryDisplaysEnabled} is {@code true}.
*/
@Nullable
@GuardedBy("mLock")
private final SparseIntArray mExtraDisplaysAssignedToUsers;
/**
* Mapping from each started user to its profile group.
@@ -137,7 +149,13 @@ public final class UserVisibilityMediator implements Dumpable {
@VisibleForTesting
UserVisibilityMediator(boolean backgroundUsersOnDisplaysEnabled, Handler handler) {
mVisibleBackgroundUsersEnabled = backgroundUsersOnDisplaysEnabled;
mUsersOnDisplaysMap = mVisibleBackgroundUsersEnabled ? new SparseIntArray() : null;
if (mVisibleBackgroundUsersEnabled) {
mUsersAssignedToDisplayOnStart = new SparseIntArray();
mExtraDisplaysAssignedToUsers = new SparseIntArray();
} else {
mUsersAssignedToDisplayOnStart = null;
mExtraDisplaysAssignedToUsers = 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);
@@ -207,7 +225,7 @@ public final class UserVisibilityMediator implements Dumpable {
if (DBG) {
Slogf.d(TAG, "adding user / display mapping (%d -> %d)", userId, displayId);
}
mUsersOnDisplaysMap.put(userId, displayId);
mUsersAssignedToDisplayOnStart.put(userId, displayId);
break;
case SECONDARY_DISPLAY_MAPPING_NOT_NEEDED:
if (DBG) {
@@ -341,9 +359,9 @@ public final class UserVisibilityMediator implements Dumpable {
}
// Check if display is available
for (int i = 0; i < mUsersOnDisplaysMap.size(); i++) {
int assignedUserId = mUsersOnDisplaysMap.keyAt(i);
int assignedDisplayId = mUsersOnDisplaysMap.valueAt(i);
for (int i = 0; i < mUsersAssignedToDisplayOnStart.size(); i++) {
int assignedUserId = mUsersAssignedToDisplayOnStart.keyAt(i);
int assignedDisplayId = mUsersAssignedToDisplayOnStart.valueAt(i);
if (DBG) {
Slogf.d(TAG, "%d: assignedUserId=%d, assignedDisplayId=%d",
i, assignedUserId, assignedDisplayId);
@@ -362,6 +380,100 @@ public final class UserVisibilityMediator implements Dumpable {
return SECONDARY_DISPLAY_MAPPING_NEEDED;
}
/**
* See {@link UserManagerInternal#assignUserToExtraDisplay(int, int)}.
*/
public boolean assignUserToExtraDisplay(@UserIdInt int userId, int displayId) {
if (DBG) {
Slogf.d(TAG, "assignUserToExtraDisplay(%d, %d)", userId, displayId);
}
if (!mVisibleBackgroundUsersEnabled) {
Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): called when not supported", userId,
displayId);
return false;
}
if (displayId == INVALID_DISPLAY) {
Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): called with INVALID_DISPLAY", userId,
displayId);
return false;
}
if (displayId == DEFAULT_DISPLAY) {
Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): DEFAULT_DISPLAY is automatically "
+ "assigned to current user", userId, displayId);
return false;
}
synchronized (mLock) {
if (!isUserVisible(userId)) {
Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): failed because user is not visible",
userId, displayId);
return false;
}
if (isStartedProfile(userId)) {
Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): failed because user is a profile",
userId, displayId);
return false;
}
if (mExtraDisplaysAssignedToUsers.get(displayId, USER_NULL) == userId) {
Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): failed because user is already "
+ "assigned to that display", userId, displayId);
return false;
}
int userAssignedToDisplay = getUserAssignedToDisplay(displayId,
/* returnCurrentUserByDefault= */ false);
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;
}
userAssignedToDisplay = mExtraDisplaysAssignedToUsers.get(userId, USER_NULL);
if (userAssignedToDisplay != USER_NULL) {
Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): failed because user %d was already "
+ "assigned that extra display", userId, displayId, userAssignedToDisplay);
return false;
}
if (DBG) {
Slogf.d(TAG, "addding %d -> %d to map", displayId, userId);
}
mExtraDisplaysAssignedToUsers.put(displayId, userId);
}
return true;
}
/**
* See {@link UserManagerInternal#unassignUserFromExtraDisplay(int, int)}.
*/
public boolean unassignUserFromExtraDisplay(@UserIdInt int userId, int displayId) {
if (DBG) {
Slogf.d(TAG, "unassignUserFromExtraDisplay(%d, %d)", userId, displayId);
}
if (!mVisibleBackgroundUsersEnabled) {
Slogf.w(TAG, "unassignUserFromExtraDisplay(%d, %d): called when not supported",
userId, displayId);
return false;
}
synchronized (mLock) {
int assignedUserId = mExtraDisplaysAssignedToUsers.get(displayId, USER_NULL);
if (assignedUserId == USER_NULL) {
Slogf.w(TAG, "unassignUserFromExtraDisplay(%d, %d): not assigned to any user",
userId, displayId);
return false;
}
if (assignedUserId != userId) {
Slogf.w(TAG, "unassignUserFromExtraDisplay(%d, %d): was assigned to user %d",
userId, displayId, assignedUserId);
return false;
}
if (DBG) {
Slogf.d(TAG, "removing %d from map", displayId);
}
mExtraDisplaysAssignedToUsers.delete(displayId);
}
return true;
}
/**
* See {@link UserManagerInternal#unassignUserFromDisplayOnStop(int)}.
*/
@@ -373,7 +485,7 @@ public final class UserVisibilityMediator implements Dumpable {
synchronized (mLock) {
visibleUsersBefore = getVisibleUsers();
unassignUserFromDisplayOnStopLocked(userId);
unassignUserFromAllDisplaysOnStopLocked(userId);
visibleUsersAfter = getVisibleUsers();
}
@@ -381,7 +493,7 @@ public final class UserVisibilityMediator implements Dumpable {
}
@GuardedBy("mLock")
private void unassignUserFromDisplayOnStopLocked(@UserIdInt int userId) {
private void unassignUserFromAllDisplaysOnStopLocked(@UserIdInt int userId) {
if (DBG) {
Slogf.d(TAG, "Removing %d from mStartedProfileGroupIds (%s)", userId,
mStartedProfileGroupIds);
@@ -395,10 +507,21 @@ public final class UserVisibilityMediator implements Dumpable {
return;
}
if (DBG) {
Slogf.d(TAG, "Removing %d from mUsersOnSecondaryDisplays (%s)", userId,
mUsersOnDisplaysMap);
Slogf.d(TAG, "Removing user %d from mUsersOnDisplaysMap (%s)", userId,
mUsersAssignedToDisplayOnStart);
}
mUsersAssignedToDisplayOnStart.delete(userId);
// Remove extra displays as well
for (int i = mExtraDisplaysAssignedToUsers.size() - 1; i >= 0; i--) {
if (mExtraDisplaysAssignedToUsers.valueAt(i) == userId) {
if (DBG) {
Slogf.d(TAG, "Removing display %d from mExtraDisplaysAssignedToUsers (%s)",
mExtraDisplaysAssignedToUsers.keyAt(i), mExtraDisplaysAssignedToUsers);
}
mExtraDisplaysAssignedToUsers.removeAt(i);
}
}
mUsersOnDisplaysMap.delete(userId);
}
/**
@@ -424,7 +547,7 @@ public final class UserVisibilityMediator implements Dumpable {
boolean visible;
synchronized (mLock) {
visible = mUsersOnDisplaysMap.indexOfKey(userId) >= 0;
visible = mUsersAssignedToDisplayOnStart.indexOfKey(userId) >= 0;
}
if (DBG) {
Slogf.d(TAG, "isUserVisible(%d): %b from mapping", userId, visible);
@@ -448,7 +571,12 @@ public final class UserVisibilityMediator implements Dumpable {
}
synchronized (mLock) {
return mUsersOnDisplaysMap.get(userId, Display.INVALID_DISPLAY) == displayId;
if (mUsersAssignedToDisplayOnStart.get(userId, Display.INVALID_DISPLAY) == displayId) {
// User assigned to display on start
return true;
}
// Check for extra assignment
return mExtraDisplaysAssignedToUsers.get(displayId, USER_NULL) == userId;
}
}
@@ -465,24 +593,34 @@ public final class UserVisibilityMediator implements Dumpable {
}
synchronized (mLock) {
return mUsersOnDisplaysMap.get(userId, Display.INVALID_DISPLAY);
return mUsersAssignedToDisplayOnStart.get(userId, Display.INVALID_DISPLAY);
}
}
/**
* See {@link UserManagerInternal#getUserAssignedToDisplay(int)}.
*/
public int getUserAssignedToDisplay(@UserIdInt int displayId) {
if (displayId == Display.DEFAULT_DISPLAY || !mVisibleBackgroundUsersEnabled) {
public @UserIdInt int getUserAssignedToDisplay(@UserIdInt int displayId) {
return getUserAssignedToDisplay(displayId, /* returnCurrentUserByDefault= */ true);
}
/**
* 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}).
*/
private @UserIdInt int getUserAssignedToDisplay(@UserIdInt int displayId,
boolean returnCurrentUserByDefault) {
if (returnCurrentUserByDefault
&& (displayId == Display.DEFAULT_DISPLAY || !mVisibleBackgroundUsersEnabled)) {
return getCurrentUserId();
}
synchronized (mLock) {
for (int i = 0; i < mUsersOnDisplaysMap.size(); i++) {
if (mUsersOnDisplaysMap.valueAt(i) != displayId) {
for (int i = 0; i < mUsersAssignedToDisplayOnStart.size(); i++) {
if (mUsersAssignedToDisplayOnStart.valueAt(i) != displayId) {
continue;
}
int userId = mUsersOnDisplaysMap.keyAt(i);
int userId = mUsersAssignedToDisplayOnStart.keyAt(i);
if (!isStartedProfile(userId)) {
return userId;
} else if (DBG) {
@@ -491,6 +629,13 @@ public final class UserVisibilityMediator implements Dumpable {
}
}
}
if (!returnCurrentUserByDefault) {
if (DBG) {
Slogf.d(TAG, "getUserAssignedToDisplay(%d): no user assigned to display, returning "
+ "USER_NULL instead", displayId);
}
return USER_NULL;
}
int currentUserId = getCurrentUserId();
if (DBG) {
@@ -618,9 +763,11 @@ public final class UserVisibilityMediator implements Dumpable {
ipw.print("Supports visible background users on displays: ");
ipw.println(mVisibleBackgroundUsersEnabled);
if (mUsersOnDisplaysMap != null) {
dumpSparseIntArray(ipw, mUsersOnDisplaysMap, "user / display", "u", "d");
}
dumpSparseIntArray(ipw, mUsersAssignedToDisplayOnStart, "user / display", "u", "d");
dumpSparseIntArray(ipw, mExtraDisplaysAssignedToUsers, "extra display / user",
"d", "u");
int numberListeners = mListeners.size();
ipw.print("Number of listeners: ");
ipw.println(numberListeners);
@@ -638,8 +785,14 @@ public final class UserVisibilityMediator implements Dumpable {
ipw.decreaseIndent();
}
private static void dumpSparseIntArray(IndentingPrintWriter ipw, SparseIntArray array,
private static void dumpSparseIntArray(IndentingPrintWriter ipw, @Nullable SparseIntArray array,
String arrayDescription, String keyName, String valueName) {
if (array == null) {
ipw.print("No ");
ipw.print(arrayDescription);
ipw.println(" mappings");
return;
}
ipw.print("Number of ");
ipw.print(arrayDescription);
ipw.print(" mappings: ");

View File

@@ -49,6 +49,7 @@ public final class UserVisibilityMediatorSUSDTest extends UserVisibilityMediator
int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, FG,
DEFAULT_DISPLAY);
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
expectUserCannotBeUnassignedFromDisplay(USER_ID, DEFAULT_DISPLAY);
expectUserIsVisible(USER_ID);
expectUserIsNotVisibleOnDisplay(USER_ID, INVALID_DISPLAY);
@@ -80,6 +81,7 @@ public final class UserVisibilityMediatorSUSDTest extends UserVisibilityMediator
int result = mMediator.assignUserToDisplayOnStart(currentUserId, currentUserId, FG,
DEFAULT_DISPLAY);
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
expectUserCannotBeUnassignedFromDisplay(currentUserId, DEFAULT_DISPLAY);
expectUserIsVisible(currentUserId);
expectUserIsNotVisibleOnDisplay(currentUserId, INVALID_DISPLAY);
@@ -110,6 +112,7 @@ public final class UserVisibilityMediatorSUSDTest extends UserVisibilityMediator
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);

View File

@@ -165,12 +165,16 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
expectNoDisplayAssignedToUser(USER_ID);
expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY);
assertInvisibleUserCannotBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID);
listener.verify();
}
@Test
public final void testStartVisibleBgUser_onDefaultDisplay() throws Exception {
visibleBgUserCannotBeStartedOnDefaultDisplayTest();
assertInvisibleUserCannotBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID);
}
protected final void visibleBgUserCannotBeStartedOnDefaultDisplayTest() throws Exception {
@@ -180,8 +184,8 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
DEFAULT_DISPLAY);
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
expectUserIsNotVisibleAtAll(USER_ID);
expectNoDisplayAssignedToUser(USER_ID);
listener.verify();
}
@@ -194,8 +198,11 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
SECONDARY_DISPLAY_ID);
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
expectUserIsNotVisibleAtAll(USER_ID);
expectNoDisplayAssignedToUser(USER_ID);
assertInvisibleUserCannotBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID);
assertInvisibleUserCannotBeAssignedExtraDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID);
listener.verify();
}
@@ -217,6 +224,9 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
expectNoDisplayAssignedToUser(USER_SYSTEM);
expectUserAssignedToDisplay(SECONDARY_DISPLAY_ID, USER_ID);
assertUserCannotBeAssignedExtraDisplay(USER_SYSTEM, SECONDARY_DISPLAY_ID);
assertUserCannotBeAssignedExtraDisplay(USER_SYSTEM, OTHER_SECONDARY_DISPLAY_ID);
listener.verify();
}
@@ -256,6 +266,8 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
expectUserAssignedToDisplay(DEFAULT_DISPLAY, OTHER_USER_ID);
assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
listener.verify();
}
@@ -289,6 +301,8 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY);
assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
listener.verify();
}
@@ -305,6 +319,10 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
expectInitialCurrentUserAssignedToDisplay(SECONDARY_DISPLAY_ID);
assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID,
OTHER_SECONDARY_DISPLAY_ID);
listener.verify();
}
@@ -320,6 +338,10 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
expectInitialCurrentUserAssignedToDisplay(SECONDARY_DISPLAY_ID);
assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID,
OTHER_SECONDARY_DISPLAY_ID);
listener.verify();
}
@@ -336,6 +358,9 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY);
assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY);
assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
listener.verify();
}
@@ -351,6 +376,10 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
expectInitialCurrentUserAssignedToDisplay(SECONDARY_DISPLAY_ID);
assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID,
OTHER_SECONDARY_DISPLAY_ID);
listener.verify();
}
@@ -481,6 +510,63 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
.that(actualResult).isEqualTo(expectedResult);
}
protected void assertBgUserBecomesInvisibleOnStop(@UserIdInt int userId) {
Log.d(TAG, "Stopping user " + userId);
mMediator.unassignUserFromDisplayOnStop(userId);
expectUserIsNotVisibleAtAll(userId);
}
/**
* Assigns and unassigns the user to / from an extra display, asserting the visibility state in
* between.
*
* <p>It assumes the user was not visible in the display beforehand.
*/
protected void assertUserCanBeAssignedExtraDisplay(@UserIdInt int userId, int displayId) {
assertUserCanBeAssignedExtraDisplay(userId, displayId, /* unassign= */ true);
}
protected void assertUserCanBeAssignedExtraDisplay(@UserIdInt int userId, int displayId,
boolean unassign) {
expectUserIsNotVisibleOnDisplay(userId, displayId);
Log.d(TAG, "Calling assignUserToExtraDisplay(" + userId + ", " + displayId + ")");
assertWithMessage("assignUserToExtraDisplay(%s, %s)", userId, displayId)
.that(mMediator.assignUserToExtraDisplay(userId, displayId))
.isTrue();
expectUserIsVisibleOnDisplay(userId, displayId);
if (unassign) {
Log.d(TAG, "Calling unassignUserFromExtraDisplay(" + userId + ", " + displayId + ")");
assertWithMessage("unassignUserFromExtraDisplay(%s, %s)", userId, displayId)
.that(mMediator.unassignUserFromExtraDisplay(userId, displayId))
.isTrue();
expectUserIsNotVisibleOnDisplay(userId, displayId);
}
}
/**
* Asserts that a user (already visible or not) cannot be assigned to an extra display (and
* hence won't be visible on that display).
*/
protected void assertUserCannotBeAssignedExtraDisplay(@UserIdInt int userId, int displayId) {
expectWithMessage("assignUserToExtraDisplay(%s, %s)", userId, displayId)
.that(mMediator.assignUserToExtraDisplay(userId, displayId))
.isFalse();
expectUserIsNotVisibleOnDisplay(userId, displayId);
}
/**
* Asserts that an invisible user cannot be assigned to an extra display.
*/
protected void assertInvisibleUserCannotBeAssignedExtraDisplay(@UserIdInt int userId,
int displayId) {
assertUserCannotBeAssignedExtraDisplay(userId, displayId);
expectNoDisplayAssignedToUser(userId);
expectInitialCurrentUserAssignedToDisplay(displayId);
}
protected void expectUserIsVisible(@UserIdInt int userId) {
expectWithMessage("isUserVisible(%s)", userId)
.that(mMediator.isUserVisible(userId))
@@ -534,6 +620,11 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
.that(mMediator.getDisplayAssignedToUser(userId)).isEqualTo(INVALID_DISPLAY);
}
protected void expectUserCannotBeUnassignedFromDisplay(@UserIdInt int userId, int displayId) {
expectWithMessage("unassignUserFromExtraDisplay(%s, %s)", userId, displayId)
.that(mMediator.unassignUserFromExtraDisplay(userId, displayId)).isFalse();
}
protected void expectUserAssignedToDisplay(int displayId, @UserIdInt int userId) {
expectWithMessage("getUserAssignedToDisplay(%s)", displayId)
.that(mMediator.getUserAssignedToDisplay(displayId)).isEqualTo(userId);

View File

@@ -52,6 +52,7 @@ abstract class UserVisibilityMediatorVisibleBackgroundUserTestCase
int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, FG,
DEFAULT_DISPLAY);
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
expectUserCannotBeUnassignedFromDisplay(USER_ID, DEFAULT_DISPLAY);
expectUserIsVisible(USER_ID);
expectUserIsVisibleOnDisplay(USER_ID, DEFAULT_DISPLAY);
@@ -64,7 +65,9 @@ abstract class UserVisibilityMediatorVisibleBackgroundUserTestCase
expectUserAssignedToDisplay(INVALID_DISPLAY, USER_ID);
expectUserAssignedToDisplay(SECONDARY_DISPLAY_ID, USER_ID);
expectDisplayAssignedToUser(USER_NULL, INVALID_DISPLAY);
expectNoDisplayAssignedToUser(USER_NULL);
assertUserCanBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID);
listener.verify();
}
@@ -83,6 +86,7 @@ abstract class UserVisibilityMediatorVisibleBackgroundUserTestCase
int result = mMediator.assignUserToDisplayOnStart(currentUserId, currentUserId, FG,
DEFAULT_DISPLAY);
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
expectUserCannotBeUnassignedFromDisplay(currentUserId, DEFAULT_DISPLAY);
expectUserIsVisible(currentUserId);
expectUserIsVisibleOnDisplay(currentUserId, DEFAULT_DISPLAY);
@@ -98,6 +102,8 @@ abstract class UserVisibilityMediatorVisibleBackgroundUserTestCase
expectUserIsNotVisibleAtAll(previousCurrentUserId);
expectNoDisplayAssignedToUser(previousCurrentUserId);
assertUserCanBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID);
listener.verify();
}
@@ -113,6 +119,7 @@ abstract class UserVisibilityMediatorVisibleBackgroundUserTestCase
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);
@@ -123,6 +130,8 @@ abstract class UserVisibilityMediatorVisibleBackgroundUserTestCase
expectDisplayAssignedToUser(PROFILE_USER_ID, DEFAULT_DISPLAY);
expectUserAssignedToDisplay(DEFAULT_DISPLAY, PARENT_USER_ID);
assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
listener.verify();
}
@@ -134,6 +143,9 @@ abstract class UserVisibilityMediatorVisibleBackgroundUserTestCase
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
assertInvisibleUserCannotBeAssignedExtraDisplay(USER_ID, DEFAULT_DISPLAY);
assertInvisibleUserCannotBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID);
listener.verify();
}
@@ -148,6 +160,9 @@ abstract class UserVisibilityMediatorVisibleBackgroundUserTestCase
expectUserIsNotVisibleAtAll(USER_ID);
assertInvisibleUserCannotBeAssignedExtraDisplay(USER_ID, DEFAULT_DISPLAY);
assertInvisibleUserCannotBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID);
listener.verify();
}
@@ -159,6 +174,7 @@ abstract class UserVisibilityMediatorVisibleBackgroundUserTestCase
int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, BG_VISIBLE,
SECONDARY_DISPLAY_ID);
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
expectUserCannotBeUnassignedFromDisplay(USER_ID, SECONDARY_DISPLAY_ID);
expectUserIsVisible(USER_ID);
expectUserIsVisibleOnDisplay(USER_ID, SECONDARY_DISPLAY_ID);
@@ -169,7 +185,16 @@ abstract class UserVisibilityMediatorVisibleBackgroundUserTestCase
expectDisplayAssignedToUser(USER_ID, SECONDARY_DISPLAY_ID);
expectUserAssignedToDisplay(SECONDARY_DISPLAY_ID, USER_ID);
listener.verify();
assertUserCanBeAssignedExtraDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID);
// Assign again, without unassigning (to make sure it becomes invisible on stop)
AsyncUserVisibilityListener listener2 = addListenerForEvents(onInvisible(USER_ID));
assertUserCanBeAssignedExtraDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID,
/* unassign= */ false);
assertBgUserBecomesInvisibleOnStop(USER_ID);
listener2.verify();
}
@Test
@@ -203,6 +228,8 @@ abstract class UserVisibilityMediatorVisibleBackgroundUserTestCase
expectNoDisplayAssignedToUser(USER_ID);
expectUserAssignedToDisplay(SECONDARY_DISPLAY_ID, OTHER_USER_ID);
assertUserCannotBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID);
listener.verify();
}
@@ -226,7 +253,18 @@ abstract class UserVisibilityMediatorVisibleBackgroundUserTestCase
expectDisplayAssignedToUser(USER_ID, OTHER_SECONDARY_DISPLAY_ID);
expectUserAssignedToDisplay(OTHER_SECONDARY_DISPLAY_ID, USER_ID);
assertUserCanBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID);
listener.verify();
// Assign again, without unassigning (to make sure it becomes invisible on stop)
AsyncUserVisibilityListener listener2 = addListenerForEvents(onInvisible(USER_ID));
assertUserCanBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID,
/* unassign= */ false);
assertBgUserBecomesInvisibleOnStop(USER_ID);
listener2.verify();
}
@Test
@@ -244,12 +282,14 @@ abstract class UserVisibilityMediatorVisibleBackgroundUserTestCase
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
expectUserAssignedToDisplay(OTHER_SECONDARY_DISPLAY_ID, PARENT_USER_ID);
assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
listener.verify();
}
// Conditions below are asserted on other tests, but they're explicitly checked in the 2
// tests below (which call this method) as well
private void currentUserVisibilityWhenNoDisplayIsAssignedTest(@UserIdInt int currentUserId) {
// Conditions below are asserted on other tests, but they're explicitly checked in the 2
// tests below as well
expectUserIsVisible(currentUserId);
expectUserIsVisibleOnDisplay(currentUserId, DEFAULT_DISPLAY);
expectUserIsNotVisibleOnDisplay(currentUserId, SECONDARY_DISPLAY_ID);
@@ -277,4 +317,13 @@ abstract class UserVisibilityMediatorVisibleBackgroundUserTestCase
expectUserIsNotVisibleAtAll(INITIAL_CURRENT_USER_ID);
expectDisplayAssignedToUser(INITIAL_CURRENT_USER_ID, INVALID_DISPLAY);
}
@Test
public final void testAssignUserToExtraDisplay_invalidDisplays() throws Exception {
expectWithMessage("assignUserToExtraDisplay(%s, %s)", USER_ID, INVALID_DISPLAY)
.that(mMediator.assignUserToExtraDisplay(USER_ID, INVALID_DISPLAY)).isFalse();
// DEFAULT_DISPLAY is always assigned to the current user
expectWithMessage("assignUserToExtraDisplay(%s, %s)", USER_ID, DEFAULT_DISPLAY)
.that(mMediator.assignUserToExtraDisplay(USER_ID, DEFAULT_DISPLAY)).isFalse();
}
}