Merge "UserVisibilityMediator refactoring, step 1."

This commit is contained in:
Felipe Leme
2022-11-10 18:34:16 +00:00
committed by Android (Google) Code Review
10 changed files with 579 additions and 185 deletions

View File

@@ -1650,7 +1650,12 @@ class UserController implements Handler.Callback {
return false;
}
mInjector.getUserManagerInternal().assignUserToDisplay(userId, displayId);
if (!userInfo.preCreated) {
// TODO(b/244644281): UMI should return whether the user is visible. And if fails,
// the user should not be in the mediator's started users structure
mInjector.getUserManagerInternal().assignUserToDisplay(userId,
userInfo.profileGroupId, foreground, displayId);
}
// TODO(b/239982558): might need something similar for bg users on secondary display
if (foreground && isUserSwitchUiEnabled()) {
@@ -1716,6 +1721,9 @@ class UserController implements Handler.Callback {
userSwitchUiEnabled = mUserSwitchUiEnabled;
}
mInjector.updateUserConfiguration();
// TODO(b/244644281): updateProfileRelatedCaches() is called on both if and else
// parts, ideally it should be moved outside, but for now it's not as there are many
// calls to external components here afterwards
updateProfileRelatedCaches();
mInjector.getWindowManager().setCurrentUser(userId);
mInjector.reportCurWakefulnessUsageEvent();

View File

@@ -348,13 +348,18 @@ public abstract class UserManagerInternal {
* <p>On most devices this call will be a no-op, but it will be used on devices that support
* multiple users on multiple displays (like automotives with passenger displays).
*
* <p><b>NOTE: </b>this method is meant to be used only by {@code UserController} (when a user
* is started)
*
* <p><b>NOTE: </b>this method doesn't validate if the display exists, it's up to the caller to
* check it. In fact, one of the intended clients for this method is
* {@code DisplayManagerService}, which will call it when a virtual display is created (another
* client is {@code UserController}, which will call it when a user is started).
*
*/
public abstract void assignUserToDisplay(@UserIdInt int userId, int displayId);
// TODO(b/244644281): rename to assignUserToDisplayOnStart() and make sure it's called on boot
// as well
public abstract void assignUserToDisplay(@UserIdInt int userId, @UserIdInt int profileGroupId,
boolean foreground, int displayId);
/**
* Unassigns a user from its current display.
@@ -363,7 +368,7 @@ public abstract class UserManagerInternal {
* multiple users on multiple displays (like automotives with passenger displays).
*
* <p><b>NOTE: </b>this method is meant to be used only by {@code UserController} (when a user
* is stopped) and {@code DisplayManagerService} (when a virtual display is destroyed).
* is stopped).
*/
public abstract void unassignUserFromDisplay(@UserIdInt int userId);

View File

@@ -633,7 +633,7 @@ public class UserManagerService extends IUserManager.Stub {
@GuardedBy("mUserStates")
private final WatchedUserStates mUserStates = new WatchedUserStates();
private final UserVisibilityMediator mUserVisibilityMediator;
private final UserVisibilityMediator mUserVisibilityMediator = new UserVisibilityMediator();
private static UserManagerService sInstance;
@@ -756,7 +756,6 @@ public class UserManagerService extends IUserManager.Stub {
mUserStates.put(UserHandle.USER_SYSTEM, UserState.STATE_BOOTING);
mUser0Allocations = DBG_ALLOCATION ? new AtomicInteger() : null;
emulateSystemUserModeIfNeeded();
mUserVisibilityMediator = new UserVisibilityMediator(this);
}
void systemReady() {
@@ -6154,7 +6153,7 @@ public class UserManagerService extends IUserManager.Stub {
dumpUser(pw, UserHandle.parseUserArg(args[1]), sb, now, nowRealtime);
return;
case "--visibility-mediator":
mUserVisibilityMediator.dump(pw);
mUserVisibilityMediator.dump(pw, args);
return;
}
}
@@ -6220,7 +6219,7 @@ public class UserManagerService extends IUserManager.Stub {
} // synchronized (mPackagesLock)
pw.println();
mUserVisibilityMediator.dump(pw);
mUserVisibilityMediator.dump(pw, args);
pw.println();
// Dump some capabilities
@@ -6799,13 +6798,16 @@ public class UserManagerService extends IUserManager.Stub {
}
@Override
public void assignUserToDisplay(@UserIdInt int userId, int displayId) {
mUserVisibilityMediator.assignUserToDisplay(userId, displayId);
public void assignUserToDisplay(@UserIdInt int userId, @UserIdInt int profileGroupId,
boolean foreground, int displayId) {
mUserVisibilityMediator.startUser(userId, profileGroupId, foreground, displayId);
mUserVisibilityMediator.assignUserToDisplay(userId, profileGroupId, displayId);
}
@Override
public void unassignUserFromDisplay(@UserIdInt int userId) {
mUserVisibilityMediator.unassignUserFromDisplay(userId);
mUserVisibilityMediator.stopUser(userId);
}
@Override

View File

@@ -15,10 +15,18 @@
*/
package com.android.server.pm;
import static android.content.pm.UserInfo.NO_PROFILE_GROUP_ID;
import static android.os.UserHandle.USER_CURRENT;
import static android.os.UserHandle.USER_NULL;
import static android.view.Display.DEFAULT_DISPLAY;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.DebugUtils;
import android.util.Dumpable;
import android.util.IndentingPrintWriter;
import android.util.SparseIntArray;
import android.view.Display;
@@ -29,6 +37,8 @@ import com.android.internal.util.Preconditions;
import com.android.server.utils.Slogf;
import java.io.PrintWriter;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Class responsible for deciding whether a user is visible (or visible for a given display).
@@ -36,72 +46,146 @@ import java.io.PrintWriter;
* <p>This class is thread safe.
*/
// TODO(b/244644281): improve javadoc (for example, explain all cases / modes)
public final class UserVisibilityMediator {
public final class UserVisibilityMediator implements Dumpable {
private static final boolean DBG = false; // DO NOT SUBMIT WITH TRUE
private static final String TAG = UserVisibilityMediator.class.getSimpleName();
private final Object mLock = new Object();
private static final String PREFIX_START_USER_RESULT = "START_USER_";
// TODO(b/244644281): should not depend on service, but keep its own internal state (like
// current user and profile groups), but it is initially as the code was just moved from UMS
// "as is". Similarly, it shouldn't need to pass the SparseIntArray on constructor (which was
// added to UMS for testing purposes)
private final UserManagerService mService;
// NOTE: it's set as USER_CURRENT instead of USER_NULL because NO_PROFILE_GROUP_ID has the same
// falue of USER_NULL, which would complicate some checks (especially on unit tests)
@VisibleForTesting
static final int INITIAL_CURRENT_USER_ID = USER_CURRENT;
public static final int START_USER_RESULT_SUCCESS_VISIBLE = 1;
public static final int START_USER_RESULT_SUCCESS_INVISIBLE = 2;
public static final int START_USER_RESULT_FAILURE = -1;
@IntDef(flag = false, prefix = {PREFIX_START_USER_RESULT}, value = {
START_USER_RESULT_SUCCESS_VISIBLE,
START_USER_RESULT_SUCCESS_INVISIBLE,
START_USER_RESULT_FAILURE
})
public @interface StartUserResult {}
private final Object mLock = new Object();
private final boolean mUsersOnSecondaryDisplaysEnabled;
@UserIdInt
@GuardedBy("mLock")
private int mCurrentUserId = INITIAL_CURRENT_USER_ID;
@Nullable
@GuardedBy("mLock")
private final SparseIntArray mUsersOnSecondaryDisplays;
private final SparseIntArray mUsersOnSecondaryDisplays = new SparseIntArray();
UserVisibilityMediator(UserManagerService service) {
this(service, UserManager.isUsersOnSecondaryDisplaysEnabled(),
/* usersOnSecondaryDisplays= */ null);
/**
* Mapping from each started user to its profile group.
*/
@GuardedBy("mLock")
private final SparseIntArray mStartedProfileGroupIds = new SparseIntArray();
UserVisibilityMediator() {
this(UserManager.isUsersOnSecondaryDisplaysEnabled());
}
@VisibleForTesting
UserVisibilityMediator(UserManagerService service, boolean usersOnSecondaryDisplaysEnabled,
@Nullable SparseIntArray usersOnSecondaryDisplays) {
mService = service;
UserVisibilityMediator(boolean usersOnSecondaryDisplaysEnabled) {
mUsersOnSecondaryDisplaysEnabled = usersOnSecondaryDisplaysEnabled;
if (mUsersOnSecondaryDisplaysEnabled) {
mUsersOnSecondaryDisplays = usersOnSecondaryDisplays == null
? new SparseIntArray() // default behavior
: usersOnSecondaryDisplays; // passed by unit test
} else {
mUsersOnSecondaryDisplays = null;
}
/**
* TODO(b/244644281): merge with assignUserToDisplay() or add javadoc.
*/
public @StartUserResult int startUser(@UserIdInt int userId, @UserIdInt int profileGroupId,
boolean foreground, int displayId) {
int actualProfileGroupId = profileGroupId == NO_PROFILE_GROUP_ID
? userId
: profileGroupId;
if (DBG) {
Slogf.d(TAG, "startUser(%d, %d, %b, %d): actualProfileGroupId=%d",
userId, profileGroupId, foreground, displayId, actualProfileGroupId);
}
if (foreground && displayId != DEFAULT_DISPLAY) {
Slogf.w(TAG, "startUser(%d, %d, %b, %d) failed: cannot start foreground user on "
+ "secondary display", userId, actualProfileGroupId, foreground, displayId);
return START_USER_RESULT_FAILURE;
}
int visibility;
synchronized (mLock) {
if (isProfile(userId, actualProfileGroupId)) {
if (displayId != DEFAULT_DISPLAY) {
Slogf.w(TAG, "startUser(%d, %d, %b, %d) failed: cannot start profile user on "
+ "secondary display", userId, actualProfileGroupId, foreground,
displayId);
return START_USER_RESULT_FAILURE;
}
if (foreground) {
Slogf.w(TAG, "startUser(%d, %d, %b, %d) failed: cannot start profile user in "
+ "foreground");
return START_USER_RESULT_FAILURE;
} else {
boolean isParentRunning = mStartedProfileGroupIds
.get(actualProfileGroupId) == actualProfileGroupId;
if (DBG) {
Slogf.d(TAG, "profile parent running: %b", isParentRunning);
}
visibility = isParentRunning
? START_USER_RESULT_SUCCESS_VISIBLE
: START_USER_RESULT_SUCCESS_INVISIBLE;
}
} else if (foreground) {
mCurrentUserId = userId;
visibility = START_USER_RESULT_SUCCESS_VISIBLE;
} else {
visibility = START_USER_RESULT_SUCCESS_INVISIBLE;
}
if (DBG) {
Slogf.d(TAG, "adding user / profile mapping (%d -> %d) and returning %s",
userId, actualProfileGroupId, startUserResultToString(visibility));
}
mStartedProfileGroupIds.put(userId, actualProfileGroupId);
}
return visibility;
}
/**
* TODO(b/244644281): merge with unassignUserFromDisplay() or add javadoc (and unit tests)
*/
public void stopUser(@UserIdInt int userId) {
if (DBG) {
Slogf.d(TAG, "stopUser(%d)", userId);
}
synchronized (mLock) {
mStartedProfileGroupIds.delete(userId);
}
}
/**
* See {@link UserManagerInternal#assignUserToDisplay(int, int)}.
*/
public void assignUserToDisplay(int userId, int displayId) {
public void assignUserToDisplay(int userId, int profileGroupId, int displayId) {
if (DBG) {
Slogf.d(TAG, "assignUserToDisplay(%d, %d)", userId, displayId);
Slogf.d(TAG, "assignUserToDisplay(%d, %d): mUsersOnSecondaryDisplaysEnabled=%b",
userId, displayId, mUsersOnSecondaryDisplaysEnabled);
}
// NOTE: Using Boolean instead of boolean as it will be re-used below
Boolean isProfile = null;
if (displayId == Display.DEFAULT_DISPLAY) {
if (mUsersOnSecondaryDisplaysEnabled) {
// Profiles are only supported in the default display, but 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).
isProfile = isProfileUnchecked(userId);
}
if (isProfile == null || !isProfile) {
// Don't need to do anything because methods (such as isUserVisible()) already
// know that the current user (and their profiles) is assigned to the default
// display.
if (DBG) {
Slogf.d(TAG, "ignoring on default display");
}
return;
if (displayId == DEFAULT_DISPLAY
&& (!mUsersOnSecondaryDisplaysEnabled || !isProfile(userId, profileGroupId))) {
// Don't need to do anything because methods (such as isUserVisible()) already
// know that the current user (and their profiles) is assigned to the default display.
// But on MUMD devices, it 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 on default display");
}
return;
}
if (!mUsersOnSecondaryDisplaysEnabled) {
@@ -119,24 +203,21 @@ public final class UserVisibilityMediator {
Preconditions.checkArgument(userId != currentUserId,
"Cannot assign current user (%d) to other displays", currentUserId);
if (isProfile == null) {
isProfile = isProfileUnchecked(userId);
}
synchronized (mLock) {
if (isProfile) {
// Profile can only start in the same display as parent. And for simplicity,
// that display must be the DEFAULT_DISPLAY.
Preconditions.checkArgument(displayId == Display.DEFAULT_DISPLAY,
"Profile user can only be started in the default display");
int parentUserId = getProfileParentId(userId);
Preconditions.checkArgument(parentUserId == currentUserId,
"Only profile of current user can be assigned to a display");
if (DBG) {
Slogf.d(TAG, "Ignoring profile user %d on default display", userId);
}
return;
if (isProfile(userId, profileGroupId)) {
// Profile can only start in the same display as parent. And for simplicity,
// that display must be the DEFAULT_DISPLAY.
Preconditions.checkArgument(displayId == Display.DEFAULT_DISPLAY,
"Profile user can only be started in the default display");
int parentUserId = getStartedProfileGroupId(userId);
Preconditions.checkArgument(parentUserId == currentUserId,
"Only profile of current user can be assigned to a display");
if (DBG) {
Slogf.d(TAG, "Ignoring profile user %d on default display", userId);
}
return;
}
synchronized (mLock) {
// Check if display is available
for (int i = 0; i < mUsersOnSecondaryDisplays.size(); i++) {
int assignedUserId = mUsersOnSecondaryDisplays.keyAt(i);
@@ -289,7 +370,7 @@ public final class UserVisibilityMediator {
continue;
}
int userId = mUsersOnSecondaryDisplays.keyAt(i);
if (!isProfileUnchecked(userId)) {
if (!isStartedProfile(userId)) {
return userId;
} else if (DBG) {
Slogf.d(TAG, "getUserAssignedToDisplay(%d): skipping user %d because it's "
@@ -307,23 +388,42 @@ public final class UserVisibilityMediator {
}
private void dump(IndentingPrintWriter ipw) {
ipw.println("UserVisibilityManager");
ipw.println("UserVisibilityMediator");
ipw.increaseIndent();
ipw.print("Supports users on secondary displays: ");
ipw.println(mUsersOnSecondaryDisplaysEnabled);
synchronized (mLock) {
ipw.print("Current user id: ");
ipw.println(mCurrentUserId);
if (mUsersOnSecondaryDisplaysEnabled) {
ipw.print("Users on secondary displays: ");
synchronized (mLock) {
ipw.println(mUsersOnSecondaryDisplays);
ipw.print("Number of started user / profile group mappings: ");
ipw.println(mStartedProfileGroupIds.size());
if (mStartedProfileGroupIds.size() > 0) {
ipw.increaseIndent();
for (int i = 0; i < mStartedProfileGroupIds.size(); i++) {
ipw.print("User #");
ipw.print(mStartedProfileGroupIds.keyAt(i));
ipw.print(" -> profile #");
ipw.println(mStartedProfileGroupIds.valueAt(i));
}
ipw.decreaseIndent();
}
ipw.print("Supports users on secondary displays: ");
ipw.println(mUsersOnSecondaryDisplaysEnabled);
if (mUsersOnSecondaryDisplaysEnabled) {
ipw.print("Users on secondary displays: ");
synchronized (mLock) {
ipw.println(mUsersOnSecondaryDisplays);
}
}
}
ipw.decreaseIndent();
}
void dump(PrintWriter pw) {
@Override
public void dump(PrintWriter pw, String[] args) {
if (pw instanceof IndentingPrintWriter) {
dump((IndentingPrintWriter) pw);
return;
@@ -331,20 +431,70 @@ public final class UserVisibilityMediator {
dump(new IndentingPrintWriter(pw));
}
// TODO(b/244644281): remove methods below once this class caches that state
private @UserIdInt int getCurrentUserId() {
return mService.getCurrentUserId();
@VisibleForTesting
Map<Integer, Integer> getUsersOnSecondaryDisplays() {
Map<Integer, Integer> map;
synchronized (mLock) {
int size = mUsersOnSecondaryDisplays.size();
map = new LinkedHashMap<>(size);
for (int i = 0; i < size; i++) {
map.put(mUsersOnSecondaryDisplays.keyAt(i), mUsersOnSecondaryDisplays.valueAt(i));
}
}
Slogf.v(TAG, "getUsersOnSecondaryDisplays(): returning %s", map);
return map;
}
private boolean isCurrentUserOrRunningProfileOfCurrentUser(@UserIdInt int userId) {
return mService.isCurrentUserOrRunningProfileOfCurrentUser(userId);
/**
* Gets the user-friendly representation of the {@code result}.
*/
public static String startUserResultToString(@StartUserResult int result) {
return DebugUtils.constantToString(UserVisibilityMediator.class, PREFIX_START_USER_RESULT,
result);
}
private boolean isProfileUnchecked(@UserIdInt int userId) {
return mService.isProfileUnchecked(userId);
// TODO(b/244644281): methods below are needed because some APIs use the current users (full and
// profiles) state to decide whether a user is visible or not. If we decide to always store that
// info into intermediate maps, we should remove them.
@VisibleForTesting
@UserIdInt int getCurrentUserId() {
synchronized (mLock) {
return mCurrentUserId;
}
}
private @UserIdInt int getProfileParentId(@UserIdInt int userId) {
return mService.getProfileParentId(userId);
@VisibleForTesting
boolean isCurrentUserOrRunningProfileOfCurrentUser(@UserIdInt int userId) {
synchronized (mLock) {
// Special case as NO_PROFILE_GROUP_ID == USER_NULL
if (userId == USER_NULL || mCurrentUserId == USER_NULL) {
return false;
}
if (mCurrentUserId == userId) {
return true;
}
return mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID) == mCurrentUserId;
}
}
private static boolean isProfile(@UserIdInt int userId, @UserIdInt int profileGroupId) {
return profileGroupId != NO_PROFILE_GROUP_ID && profileGroupId != userId;
}
@VisibleForTesting
boolean isStartedProfile(@UserIdInt int userId) {
int profileGroupId;
synchronized (mLock) {
profileGroupId = mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID);
}
return isProfile(userId, profileGroupId);
}
@VisibleForTesting
@UserIdInt int getStartedProfileGroupId(@UserIdInt int userId) {
synchronized (mLock) {
return mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID);
}
}
}

View File

@@ -0,0 +1,91 @@
/*
* 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;
import android.util.Dumpable;
import android.util.Log;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
/**
* {@code JUnit} rule that logs (using tag {@value #TAG} the contents of
* {@link Dumpable dumpables} in case of failure.
*/
public final class DumpableDumperRule implements TestRule {
private static final String TAG = DumpableDumperRule.class.getSimpleName();
private static final String[] NO_ARGS = {};
private final List<Dumpable> mDumpables = new ArrayList<>();
/**
* Adds a {@link Dumpable} to be logged if the test case fails.
*/
public void addDumpable(Dumpable dumpable) {
mDumpables.add(dumpable);
}
@Override
public Statement apply(Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
try {
base.evaluate();
} catch (Throwable t) {
dumpOnFailure(description.getMethodName());
throw t;
}
}
};
}
private void dumpOnFailure(String testName) throws IOException {
if (mDumpables.isEmpty()) {
return;
}
Log.w(TAG, "Dumping " + mDumpables.size() + " dumpables on failure of " + testName);
mDumpables.forEach(d -> logDumpable(d));
}
private void logDumpable(Dumpable dumpable) {
try {
try (StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw)) {
dumpable.dump(pw, NO_ARGS);
String[] dump = sw.toString().split(System.lineSeparator());
Log.w(TAG, "Dumping " + dumpable.getDumpableName() + " (" + dump.length
+ " lines):");
for (String line : dump) {
Log.w(TAG, line);
}
} catch (RuntimeException e) {
Log.e(TAG, "RuntimeException dumping " + dumpable.getDumpableName(), e);
}
} catch (IOException e) {
Log.e(TAG, "IOException dumping " + dumpable.getDumpableName(), e);
}
}
}

View File

@@ -23,6 +23,7 @@ import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;
@@ -38,6 +39,9 @@ public abstract class ExtendedMockitoTestCase {
private MockitoSession mSession;
@Rule
public final DumpableDumperRule mDumpableDumperRule = new DumpableDumperRule();
@Before
public void startSession() {
if (DEBUG) {

View File

@@ -44,14 +44,14 @@ public final class UserVisibilityMediatorMUMDTest extends UserVisibilityMediator
@Test
public void testAssignUserToDisplay_systemUser() {
assertThrows(IllegalArgumentException.class,
() -> mMediator.assignUserToDisplay(USER_SYSTEM, SECONDARY_DISPLAY_ID));
assertThrows(IllegalArgumentException.class, () -> mMediator
.assignUserToDisplay(USER_SYSTEM, USER_SYSTEM, SECONDARY_DISPLAY_ID));
}
@Test
public void testAssignUserToDisplay_invalidDisplay() {
assertThrows(IllegalArgumentException.class,
() -> mMediator.assignUserToDisplay(USER_ID, INVALID_DISPLAY));
() -> mMediator.assignUserToDisplay(USER_ID, USER_ID, INVALID_DISPLAY));
}
@Test
@@ -59,7 +59,7 @@ public final class UserVisibilityMediatorMUMDTest extends UserVisibilityMediator
mockCurrentUser(USER_ID);
assertThrows(IllegalArgumentException.class,
() -> mMediator.assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID));
() -> mMediator.assignUserToDisplay(USER_ID, USER_ID, SECONDARY_DISPLAY_ID));
assertNoUserAssignedToDisplay();
}
@@ -67,11 +67,10 @@ public final class UserVisibilityMediatorMUMDTest extends UserVisibilityMediator
@Test
public void testAssignUserToDisplay_startedProfileOfCurrentUser() {
mockCurrentUser(PARENT_USER_ID);
addDefaultProfileAndParent();
startDefaultProfile();
IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
() -> mMediator.assignUserToDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID));
IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> mMediator
.assignUserToDisplay(PROFILE_USER_ID, PARENT_USER_ID, SECONDARY_DISPLAY_ID));
Log.v(TAG, "Exception: " + e);
assertNoUserAssignedToDisplay();
@@ -80,11 +79,10 @@ public final class UserVisibilityMediatorMUMDTest extends UserVisibilityMediator
@Test
public void testAssignUserToDisplay_stoppedProfileOfCurrentUser() {
mockCurrentUser(PARENT_USER_ID);
addDefaultProfileAndParent();
stopDefaultProfile();
IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
() -> mMediator.assignUserToDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID));
IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> mMediator
.assignUserToDisplay(PROFILE_USER_ID, PARENT_USER_ID, SECONDARY_DISPLAY_ID));
Log.v(TAG, "Exception: " + e);
assertNoUserAssignedToDisplay();
@@ -92,17 +90,17 @@ public final class UserVisibilityMediatorMUMDTest extends UserVisibilityMediator
@Test
public void testAssignUserToDisplay_displayAvailable() {
mMediator.assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID);
mMediator.assignUserToDisplay(USER_ID, USER_ID, SECONDARY_DISPLAY_ID);
assertUserAssignedToDisplay(USER_ID, SECONDARY_DISPLAY_ID);
}
@Test
public void testAssignUserToDisplay_displayAlreadyAssigned() {
mMediator.assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID);
mMediator.assignUserToDisplay(USER_ID, USER_ID, SECONDARY_DISPLAY_ID);
IllegalStateException e = assertThrows(IllegalStateException.class,
() -> mMediator.assignUserToDisplay(OTHER_USER_ID, SECONDARY_DISPLAY_ID));
IllegalStateException e = assertThrows(IllegalStateException.class, () -> mMediator
.assignUserToDisplay(OTHER_USER_ID, OTHER_USER_ID, SECONDARY_DISPLAY_ID));
Log.v(TAG, "Exception: " + e);
assertWithMessage("exception (%s) message", e).that(e).hasMessageThat()
@@ -112,10 +110,10 @@ public final class UserVisibilityMediatorMUMDTest extends UserVisibilityMediator
@Test
public void testAssignUserToDisplay_userAlreadyAssigned() {
mMediator.assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID);
mMediator.assignUserToDisplay(USER_ID, USER_ID, SECONDARY_DISPLAY_ID);
IllegalStateException e = assertThrows(IllegalStateException.class,
() -> mMediator.assignUserToDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID));
() -> mMediator.assignUserToDisplay(USER_ID, USER_ID, OTHER_SECONDARY_DISPLAY_ID));
Log.v(TAG, "Exception: " + e);
assertWithMessage("exception (%s) message", e).that(e).hasMessageThat()
@@ -127,11 +125,9 @@ public final class UserVisibilityMediatorMUMDTest extends UserVisibilityMediator
@Test
public void testAssignUserToDisplay_profileOnSameDisplayAsParent() {
addDefaultProfileAndParent();
mMediator.assignUserToDisplay(PARENT_USER_ID, SECONDARY_DISPLAY_ID);
IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
() -> mMediator.assignUserToDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID));
mMediator.assignUserToDisplay(PARENT_USER_ID, PARENT_USER_ID, SECONDARY_DISPLAY_ID);
IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> mMediator
.assignUserToDisplay(PROFILE_USER_ID, PARENT_USER_ID, SECONDARY_DISPLAY_ID));
Log.v(TAG, "Exception: " + e);
assertUserAssignedToDisplay(PARENT_USER_ID, SECONDARY_DISPLAY_ID);
@@ -139,11 +135,9 @@ public final class UserVisibilityMediatorMUMDTest extends UserVisibilityMediator
@Test
public void testAssignUserToDisplay_profileOnDifferentDisplayAsParent() {
addDefaultProfileAndParent();
mMediator.assignUserToDisplay(PARENT_USER_ID, SECONDARY_DISPLAY_ID);
IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
() -> mMediator.assignUserToDisplay(PROFILE_USER_ID, OTHER_SECONDARY_DISPLAY_ID));
mMediator.assignUserToDisplay(PARENT_USER_ID, PARENT_USER_ID, SECONDARY_DISPLAY_ID);
IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> mMediator
.assignUserToDisplay(PROFILE_USER_ID, PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID));
Log.v(TAG, "Exception: " + e);
assertUserAssignedToDisplay(PARENT_USER_ID, SECONDARY_DISPLAY_ID);
@@ -151,11 +145,9 @@ public final class UserVisibilityMediatorMUMDTest extends UserVisibilityMediator
@Test
public void testAssignUserToDisplay_profileDefaultDisplayParentOnSecondaryDisplay() {
addDefaultProfileAndParent();
mMediator.assignUserToDisplay(PARENT_USER_ID, SECONDARY_DISPLAY_ID);
IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
() -> mMediator.assignUserToDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY));
mMediator.assignUserToDisplay(PARENT_USER_ID, PARENT_USER_ID, SECONDARY_DISPLAY_ID);
IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> mMediator
.assignUserToDisplay(PROFILE_USER_ID, PARENT_USER_ID, DEFAULT_DISPLAY));
Log.v(TAG, "Exception: " + e);
assertUserAssignedToDisplay(PARENT_USER_ID, SECONDARY_DISPLAY_ID);
@@ -201,7 +193,6 @@ public final class UserVisibilityMediatorMUMDTest extends UserVisibilityMediator
@Test
public void testIsUserVisibleOnDisplay_startedProfileOfCurrentUserSecondaryDisplayAssignedToAnotherUser() {
addDefaultProfileAndParent();
startDefaultProfile();
mockCurrentUser(PARENT_USER_ID);
assignUserToDisplay(OTHER_USER_ID, SECONDARY_DISPLAY_ID);
@@ -212,7 +203,6 @@ public final class UserVisibilityMediatorMUMDTest extends UserVisibilityMediator
@Test
public void testIsUserVisibleOnDisplay_stoppedProfileOfCurrentUserSecondaryDisplayAssignedToAnotherUser() {
addDefaultProfileAndParent();
stopDefaultProfile();
mockCurrentUser(PARENT_USER_ID);
assignUserToDisplay(OTHER_USER_ID, SECONDARY_DISPLAY_ID);
@@ -223,7 +213,6 @@ public final class UserVisibilityMediatorMUMDTest extends UserVisibilityMediator
@Test
public void testIsUserVisibleOnDisplay_startedProfileOfCurrentUserOnUnassignedSecondaryDisplay() {
addDefaultProfileAndParent();
startDefaultProfile();
mockCurrentUser(PARENT_USER_ID);
@@ -285,19 +274,6 @@ public final class UserVisibilityMediatorMUMDTest extends UserVisibilityMediator
.that(mMediator.getUserAssignedToDisplay(SECONDARY_DISPLAY_ID)).isEqualTo(USER_ID);
}
// TODO(b/244644281): scenario below shouldn't happen on "real life", as the profile cannot be
// started on secondary display if its parent isn't, so we might need to remove (or refactor
// this test) if/when the underlying logic changes
@Test
public void testGetUserAssignedToDisplay_profileOnSecondaryDisplay() {
addDefaultProfileAndParent();
mockCurrentUser(USER_ID);
assignUserToDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
assertWithMessage("getUserAssignedToDisplay(%s)", SECONDARY_DISPLAY_ID)
.that(mMediator.getUserAssignedToDisplay(SECONDARY_DISPLAY_ID)).isEqualTo(USER_ID);
}
// NOTE: we don't need to add tests for profiles (started / stopped profiles of bg user), as
// getUserAssignedToDisplay() for bg users relies only on the user / display assignments
}

View File

@@ -39,27 +39,25 @@ public final class UserVisibilityMediatorSUSDTest extends UserVisibilityMediator
mockCurrentUser(USER_ID);
assertThrows(UnsupportedOperationException.class,
() -> mMediator.assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID));
() -> mMediator.assignUserToDisplay(USER_ID, USER_ID, SECONDARY_DISPLAY_ID));
}
@Test
public void testAssignUserToDisplay_otherDisplay_startProfileOfcurrentUser() {
mockCurrentUser(PARENT_USER_ID);
addDefaultProfileAndParent();
startDefaultProfile();
assertThrows(UnsupportedOperationException.class,
() -> mMediator.assignUserToDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID));
assertThrows(UnsupportedOperationException.class, () -> mMediator
.assignUserToDisplay(PROFILE_USER_ID, PARENT_USER_ID, SECONDARY_DISPLAY_ID));
}
@Test
public void testAssignUserToDisplay_otherDisplay_stoppedProfileOfcurrentUser() {
mockCurrentUser(PARENT_USER_ID);
addDefaultProfileAndParent();
stopDefaultProfile();
assertThrows(UnsupportedOperationException.class,
() -> mMediator.assignUserToDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID));
assertThrows(UnsupportedOperationException.class, () -> mMediator
.assignUserToDisplay(PROFILE_USER_ID, PARENT_USER_ID, SECONDARY_DISPLAY_ID));
}
@Test

View File

@@ -15,23 +15,27 @@
*/
package com.android.server.pm;
import static android.content.pm.UserInfo.NO_PROFILE_GROUP_ID;
import static android.os.UserHandle.USER_NULL;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static com.android.server.am.UserState.STATE_RUNNING_UNLOCKED;
import static com.android.server.pm.UserVisibilityMediator.INITIAL_CURRENT_USER_ID;
import static com.android.server.pm.UserVisibilityMediator.START_USER_RESULT_FAILURE;
import static com.android.server.pm.UserVisibilityMediator.START_USER_RESULT_SUCCESS_INVISIBLE;
import static com.android.server.pm.UserVisibilityMediator.START_USER_RESULT_SUCCESS_VISIBLE;
import static com.android.server.pm.UserVisibilityMediator.startUserResultToString;
import static com.google.common.truth.Truth.assertWithMessage;
import android.annotation.UserIdInt;
import android.util.SparseIntArray;
import android.util.Log;
import com.android.server.ExtendedMockitoTestCase;
import org.junit.Before;
import org.junit.Test;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Base class for {@link UserVisibilityMediator} tests.
*
@@ -39,7 +43,33 @@ import java.util.Map;
* device mode (for example, whether the device supports concurrent multiple users on multiple
* displays or not).
*/
abstract class UserVisibilityMediatorTestCase extends UserManagerServiceOrInternalTestCase {
abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
private static final String TAG = UserVisibilityMediatorTestCase.class.getSimpleName();
/**
* Id for a simple user (that doesn't have profiles).
*/
protected static final int USER_ID = 600;
/**
* Id for another simple user.
*/
protected static final int OTHER_USER_ID = 666;
/**
* Id for a user that has one profile (whose id is {@link #PROFILE_USER_ID}.
*
* <p>You can use {@link #addDefaultProfileAndParent()} to add both of this user to the service.
*/
protected static final int PARENT_USER_ID = 642;
/**
* Id for a profile whose parent is {@link #PARENTUSER_ID}.
*
* <p>You can use {@link #addDefaultProfileAndParent()} to add both of this user to the service.
*/
protected static final int PROFILE_USER_ID = 643;
/**
* Id of a secondary display (i.e, not {@link android.view.Display.DEFAULT_DISPLAY}).
@@ -51,12 +81,10 @@ abstract class UserVisibilityMediatorTestCase extends UserManagerServiceOrIntern
*/
protected static final int OTHER_SECONDARY_DISPLAY_ID = 108;
private final boolean mUsersOnSecondaryDisplaysEnabled;
private static final boolean FG = true;
private static final boolean BG = false;
// TODO(b/244644281): manipulating mUsersOnSecondaryDisplays directly leaks implementation
// details into the unit test, but it's fine for now as the tests were copied "as is" - it
// would be better to use a geter() instead
protected final SparseIntArray mUsersOnSecondaryDisplays = new SparseIntArray();
private final boolean mUsersOnSecondaryDisplaysEnabled;
protected UserVisibilityMediator mMediator;
@@ -66,13 +94,93 @@ abstract class UserVisibilityMediatorTestCase extends UserManagerServiceOrIntern
@Before
public final void setMediator() {
mMediator = new UserVisibilityMediator(mUms, mUsersOnSecondaryDisplaysEnabled,
mUsersOnSecondaryDisplays);
mMediator = new UserVisibilityMediator(mUsersOnSecondaryDisplaysEnabled);
mDumpableDumperRule.addDumpable(mMediator);
}
@Test
public final void testStartUser_currentUser() {
int result = mMediator.startUser(USER_ID, USER_ID, FG, DEFAULT_DISPLAY);
assertStartUserResult(result, START_USER_RESULT_SUCCESS_VISIBLE);
assertCurrentUser(USER_ID);
assertIsCurrentUserOrRunningProfileOfCurrentUser(USER_ID);
assertStartedProfileGroupIdOf(USER_ID, USER_ID);
}
@Test
public final void testStartUser_currentUserSecondaryDisplay() {
int result = mMediator.startUser(USER_ID, USER_ID, FG, SECONDARY_DISPLAY_ID);
assertStartUserResult(result, START_USER_RESULT_FAILURE);
assertCurrentUser(INITIAL_CURRENT_USER_ID);
assertIsNotCurrentUserOrRunningProfileOfCurrentUser(USER_ID);
assertStartedProfileGroupIdOf(USER_ID, NO_PROFILE_GROUP_ID);
}
@Test
public final void testStartUser_profileBg_parentStarted() {
mockCurrentUser(PARENT_USER_ID);
int result = mMediator.startUser(PROFILE_USER_ID, PARENT_USER_ID, BG, DEFAULT_DISPLAY);
assertStartUserResult(result, START_USER_RESULT_SUCCESS_VISIBLE);
assertCurrentUser(PARENT_USER_ID);
assertIsCurrentUserOrRunningProfileOfCurrentUser(PROFILE_USER_ID);
assertStartedProfileGroupIdOf(PROFILE_USER_ID, PARENT_USER_ID);
assertIsStartedProfile(PROFILE_USER_ID);
}
@Test
public final void testStartUser_profileBg_parentNotStarted() {
int result = mMediator.startUser(PROFILE_USER_ID, PARENT_USER_ID, BG, DEFAULT_DISPLAY);
assertStartUserResult(result, START_USER_RESULT_SUCCESS_INVISIBLE);
assertCurrentUser(INITIAL_CURRENT_USER_ID);
assertIsNotCurrentUserOrRunningProfileOfCurrentUser(PROFILE_USER_ID);
assertStartedProfileGroupIdOf(PROFILE_USER_ID, PARENT_USER_ID);
assertIsStartedProfile(PROFILE_USER_ID);
}
@Test
public final void testStartUser_profileBg_secondaryDisplay() {
int result = mMediator.startUser(PROFILE_USER_ID, PARENT_USER_ID, BG, SECONDARY_DISPLAY_ID);
assertStartUserResult(result, START_USER_RESULT_FAILURE);
assertCurrentUser(INITIAL_CURRENT_USER_ID);
assertIsNotCurrentUserOrRunningProfileOfCurrentUser(PROFILE_USER_ID);
}
@Test
public final void testStartUser_profileFg() {
int result = mMediator.startUser(PROFILE_USER_ID, PARENT_USER_ID, FG, DEFAULT_DISPLAY);
assertStartUserResult(result, START_USER_RESULT_FAILURE);
assertCurrentUser(INITIAL_CURRENT_USER_ID);
assertIsNotCurrentUserOrRunningProfileOfCurrentUser(PROFILE_USER_ID);
assertStartedProfileGroupIdOf(PROFILE_USER_ID, NO_PROFILE_GROUP_ID);
}
@Test
public final void testStartUser_profileFgSecondaryDisplay() {
int result = mMediator.startUser(PROFILE_USER_ID, PARENT_USER_ID, FG, SECONDARY_DISPLAY_ID);
assertStartUserResult(result, START_USER_RESULT_FAILURE);
assertCurrentUser(INITIAL_CURRENT_USER_ID);
}
@Test
public final void testGetStartedProfileGroupId_whenStartedWithNoProfileGroupId() {
int result = mMediator.startUser(USER_ID, NO_PROFILE_GROUP_ID, FG, DEFAULT_DISPLAY);
assertStartUserResult(result, START_USER_RESULT_SUCCESS_VISIBLE);
assertWithMessage("shit").that(mMediator.getStartedProfileGroupId(USER_ID))
.isEqualTo(USER_ID);
}
@Test
public final void testAssignUserToDisplay_defaultDisplayIgnored() {
mMediator.assignUserToDisplay(USER_ID, DEFAULT_DISPLAY);
mMediator.assignUserToDisplay(USER_ID, USER_ID, DEFAULT_DISPLAY);
assertNoUserAssignedToDisplay();
}
@@ -103,18 +211,14 @@ abstract class UserVisibilityMediatorTestCase extends UserManagerServiceOrIntern
@Test
public final void testIsUserVisible_startedProfileOfcurrentUser() {
addDefaultProfileAndParent();
mockCurrentUser(PARENT_USER_ID);
startDefaultProfile();
setUserState(PROFILE_USER_ID, STATE_RUNNING_UNLOCKED);
assertWithMessage("isUserVisible(%s)", PROFILE_USER_ID)
.that(mMediator.isUserVisible(PROFILE_USER_ID)).isTrue();
}
@Test
public final void testIsUserVisible_stoppedProfileOfcurrentUser() {
addDefaultProfileAndParent();
mockCurrentUser(PARENT_USER_ID);
stopDefaultProfile();
@@ -164,7 +268,6 @@ abstract class UserVisibilityMediatorTestCase extends UserManagerServiceOrIntern
@Test
public final void testIsUserVisibleOnDisplay_startedProfileOfcurrentUserInvalidDisplay() {
addDefaultProfileAndParent();
mockCurrentUser(PARENT_USER_ID);
startDefaultProfile();
@@ -174,7 +277,6 @@ abstract class UserVisibilityMediatorTestCase extends UserManagerServiceOrIntern
@Test
public final void testIsUserVisibleOnDisplay_stoppedProfileOfcurrentUserInvalidDisplay() {
addDefaultProfileAndParent();
mockCurrentUser(PARENT_USER_ID);
stopDefaultProfile();
@@ -184,18 +286,14 @@ abstract class UserVisibilityMediatorTestCase extends UserManagerServiceOrIntern
@Test
public final void testIsUserVisibleOnDisplay_startedProfileOfcurrentUserDefaultDisplay() {
addDefaultProfileAndParent();
mockCurrentUser(PARENT_USER_ID);
startDefaultProfile();
setUserState(PROFILE_USER_ID, STATE_RUNNING_UNLOCKED);
assertWithMessage("isUserVisible(%s, %s)", PROFILE_USER_ID, DEFAULT_DISPLAY)
.that(mMediator.isUserVisible(PROFILE_USER_ID, DEFAULT_DISPLAY)).isTrue();
}
@Test
public final void testIsUserVisibleOnDisplay_stoppedProfileOfcurrentUserDefaultDisplay() {
addDefaultProfileAndParent();
mockCurrentUser(PARENT_USER_ID);
stopDefaultProfile();
@@ -205,18 +303,14 @@ abstract class UserVisibilityMediatorTestCase extends UserManagerServiceOrIntern
@Test
public final void testIsUserVisibleOnDisplay_startedProfileOfCurrentUserSecondaryDisplay() {
addDefaultProfileAndParent();
mockCurrentUser(PARENT_USER_ID);
startDefaultProfile();
setUserState(PROFILE_USER_ID, STATE_RUNNING_UNLOCKED);
assertWithMessage("isUserVisible(%s, %s)", PROFILE_USER_ID, SECONDARY_DISPLAY_ID)
.that(mMediator.isUserVisible(PROFILE_USER_ID, SECONDARY_DISPLAY_ID)).isTrue();
}
@Test
public void testIsUserVisibleOnDisplay_stoppedProfileOfcurrentUserSecondaryDisplay() {
addDefaultProfileAndParent();
mockCurrentUser(PARENT_USER_ID);
stopDefaultProfile();
@@ -250,11 +344,8 @@ abstract class UserVisibilityMediatorTestCase extends UserManagerServiceOrIntern
@Test
public final void testGetDisplayAssignedToUser_startedProfileOfcurrentUser() {
addDefaultProfileAndParent();
mockCurrentUser(PARENT_USER_ID);
startDefaultProfile();
setUserState(PROFILE_USER_ID, STATE_RUNNING_UNLOCKED);
assertWithMessage("getDisplayAssignedToUser(%s)", PROFILE_USER_ID)
.that(mMediator.getDisplayAssignedToUser(PROFILE_USER_ID))
.isEqualTo(DEFAULT_DISPLAY);
@@ -262,7 +353,6 @@ abstract class UserVisibilityMediatorTestCase extends UserManagerServiceOrIntern
@Test
public final void testGetDisplayAssignedToUser_stoppedProfileOfcurrentUser() {
addDefaultProfileAndParent();
mockCurrentUser(PARENT_USER_ID);
stopDefaultProfile();
@@ -296,28 +386,96 @@ abstract class UserVisibilityMediatorTestCase extends UserManagerServiceOrIntern
.isEqualTo(USER_ID);
}
// NOTE: should only called by tests that indirectly needs to check user assignments (like
// isUserVisible), not by tests for the user assignment methods per se.
// TODO(b/244644281): remove if start & assign are merged; if they aren't, add a note explaining
// it's not meant to be used to test startUser() itself.
protected void mockCurrentUser(@UserIdInt int userId) {
Log.d(TAG, "mockCurrentUser(" + userId + ")");
int result = mMediator.startUser(userId, userId, FG, DEFAULT_DISPLAY);
if (result != START_USER_RESULT_SUCCESS_VISIBLE) {
throw new IllegalStateException("Failed to mock current user " + userId
+ ": mediator returned " + startUserResultToString(result));
}
}
// TODO(b/244644281): remove if start & assign are merged; if they aren't, add a note explaining
// it's not meant to be used to test startUser() itself.
protected void startDefaultProfile() {
mockCurrentUser(PARENT_USER_ID);
Log.d(TAG, "starting default profile (" + PROFILE_USER_ID + ") in background after starting"
+ " its parent (" + PARENT_USER_ID + ") on foreground");
int result = mMediator.startUser(PROFILE_USER_ID, PARENT_USER_ID, BG, DEFAULT_DISPLAY);
if (result != START_USER_RESULT_SUCCESS_VISIBLE) {
throw new IllegalStateException("Failed to start profile user " + PROFILE_USER_ID
+ ": mediator returned " + startUserResultToString(result));
}
}
// TODO(b/244644281): remove if start & assign are merged; if they aren't, add a note explaining
// it's not meant to be used to test stopUser() itself.
protected void stopDefaultProfile() {
Log.d(TAG, "stopping default profile");
mMediator.stopUser(PROFILE_USER_ID);
}
// TODO(b/244644281): remove if start & assign are merged; if they aren't, add a note explaining
// it's not meant to be used to test assignUserToDisplay() itself.
protected final void assignUserToDisplay(@UserIdInt int userId, int displayId) {
mUsersOnSecondaryDisplays.put(userId, displayId);
Log.d(TAG, "assignUserToDisplay(" + userId + ", " + displayId + ")");
int result = mMediator.startUser(userId, userId, BG, displayId);
if (result != START_USER_RESULT_SUCCESS_INVISIBLE) {
throw new IllegalStateException("Failed to startuser " + userId
+ " on background: mediator returned " + startUserResultToString(result));
}
mMediator.assignUserToDisplay(userId, userId, displayId);
}
protected final void assertNoUserAssignedToDisplay() {
assertWithMessage("mUsersOnSecondaryDisplays()").that(usersOnSecondaryDisplaysAsMap())
assertWithMessage("uses on secondary displays")
.that(mMediator.getUsersOnSecondaryDisplays())
.isEmpty();
}
protected final void assertUserAssignedToDisplay(@UserIdInt int userId, int displayId) {
assertWithMessage("mUsersOnSecondaryDisplays()").that(usersOnSecondaryDisplaysAsMap())
assertWithMessage("uses on secondary displays")
.that(mMediator.getUsersOnSecondaryDisplays())
.containsExactly(userId, displayId);
}
private Map<Integer, Integer> usersOnSecondaryDisplaysAsMap() {
int size = mUsersOnSecondaryDisplays.size();
Map<Integer, Integer> map = new LinkedHashMap<>(size);
for (int i = 0; i < size; i++) {
map.put(mUsersOnSecondaryDisplays.keyAt(i), mUsersOnSecondaryDisplays.valueAt(i));
}
return map;
private void assertCurrentUser(@UserIdInt int userId) {
assertWithMessage("mediator.getCurrentUserId()").that(mMediator.getCurrentUserId())
.isEqualTo(userId);
}
private void assertIsStartedProfile(@UserIdInt int userId) {
assertWithMessage("mediator.isStartedProfile(%s)", userId)
.that(mMediator.isStartedProfile(userId))
.isTrue();
}
private void assertStartedProfileGroupIdOf(@UserIdInt int profileId, @UserIdInt int parentId) {
assertWithMessage("mediator.getStartedProfileGroupId(%s)", profileId)
.that(mMediator.getStartedProfileGroupId(profileId))
.isEqualTo(parentId);
}
private void assertIsCurrentUserOrRunningProfileOfCurrentUser(int userId) {
assertWithMessage("mediator.isCurrentUserOrRunningProfileOfCurrentUser(%s)", userId)
.that(mMediator.isCurrentUserOrRunningProfileOfCurrentUser(userId))
.isTrue();
}
private void assertIsNotCurrentUserOrRunningProfileOfCurrentUser(int userId) {
assertWithMessage("mediator.isCurrentUserOrRunningProfileOfCurrentUser(%s)", userId)
.that(mMediator.isCurrentUserOrRunningProfileOfCurrentUser(userId))
.isFalse();
}
private void assertStartUserResult(int actualResult, int expectedResult) {
assertWithMessage("startUser() result (where %s=%s and %s=%s)",
actualResult, startUserResultToString(actualResult),
expectedResult, startUserResultToString(expectedResult))
.that(actualResult).isEqualTo(expectedResult);
}
}

View File

@@ -285,7 +285,7 @@ public class UserControllerTest {
assertWithMessage("wrong binder message calls").that(mInjector.mHandler.getMessageCodes())
.containsExactly(USER_START_MSG);
verifyUserAssignedToDisplay(TEST_PRE_CREATED_USER_ID, Display.DEFAULT_DISPLAY);
verifyUserNeverAssignedToDisplay();
}
private void startUserAssertions(
@@ -950,11 +950,13 @@ public class UserControllerTest {
}
private void verifyUserAssignedToDisplay(@UserIdInt int userId, int displayId) {
verify(mInjector.getUserManagerInternal()).assignUserToDisplay(userId, displayId);
verify(mInjector.getUserManagerInternal()).assignUserToDisplay(eq(userId), anyInt(),
anyBoolean(), eq(displayId));
}
private void verifyUserNeverAssignedToDisplay() {
verify(mInjector.getUserManagerInternal(), never()).assignUserToDisplay(anyInt(), anyInt());
verify(mInjector.getUserManagerInternal(), never()).assignUserToDisplay(anyInt(), anyInt(),
anyBoolean(), anyInt());
}
private void verifyUserUnassignedFromDisplay(@UserIdInt int userId) {