Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 94744905 authored by Felipe Leme's avatar Felipe Leme
Browse files

New UserManagerInternal APIs for extra user / display assignment.

Currently, a user is only visible in one display, which is assigned
when the user is started. But there will be cases where the user
should be visible on multiple displays, like on cars where the
back passenger seats have 2 displays each (one "main" display and
a smaller display for user input)

Test: atest UserVisibilityMediatorSUSDTest UserVisibilityMediatorMUMDTest
Bug: 261917465

Change-Id: I824f9663ef83451239a94f656eadba138a6ae50f
parent 630e4fde
Loading
Loading
Loading
Loading
+32 −4
Original line number Original line Diff line number Diff line
@@ -388,8 +388,8 @@ public abstract class UserManagerInternal {
     * and the user is {@link UserManager#isUserVisible() visible}.
     * 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
     * <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 /
     * is started); for extra unassignments, callers should call {@link
     * display assignment, we'll need to provide other APIs.
     * #assignUserToExtraDisplay(int, int)} instead.
     *
     *
     * <p><b>NOTE: </b>this method doesn't validate if the display exists, it's up to the caller to
     * <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.
     * pass a valid display id.
@@ -397,15 +397,43 @@ public abstract class UserManagerInternal {
    public abstract @UserAssignmentResult int assignUserToDisplayOnStart(@UserIdInt int userId,
    public abstract @UserAssignmentResult int assignUserToDisplayOnStart(@UserIdInt int userId,
            @UserIdInt int profileGroupId, @UserStartMode int userStartMode, int displayId);
            @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.
     * 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
     * <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 /
     * is stopped); for extra unassignments, callers should call
     * display assignment, we'll need to provide other APIs.
     * {@link #unassignUserFromExtraDisplay(int, int)} instead.
     */
     */
    public abstract void unassignUserFromDisplayOnStop(@UserIdInt int userId);
    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
     * Returns {@code true} if the user is visible (as defined by
     * {@link UserManager#isUserVisible()}.
     * {@link UserManager#isUserVisible()}.
+10 −0
Original line number Original line Diff line number Diff line
@@ -7014,6 +7014,16 @@ public class UserManagerService extends IUserManager.Stub {
                    userStartMode, displayId);
                    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
        @Override
        public void unassignUserFromDisplayOnStop(@UserIdInt int userId) {
        public void unassignUserFromDisplayOnStop(@UserIdInt int userId) {
            mUserVisibilityMediator.unassignUserFromDisplayOnStop(userId);
            mUserVisibilityMediator.unassignUserFromDisplayOnStop(userId);
+176 −23
Original line number Original line Diff line number Diff line
@@ -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_NULL;
import static android.os.UserHandle.USER_SYSTEM;
import static android.os.UserHandle.USER_SYSTEM;
import static android.view.Display.DEFAULT_DISPLAY;
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_FAILURE;
import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE;
import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE;
@@ -113,7 +114,18 @@ public final class UserVisibilityMediator implements Dumpable {
     */
     */
    @Nullable
    @Nullable
    @GuardedBy("mLock")
    @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.
     * Mapping from each started user to its profile group.
@@ -137,7 +149,13 @@ public final class UserVisibilityMediator implements Dumpable {
    @VisibleForTesting
    @VisibleForTesting
    UserVisibilityMediator(boolean backgroundUsersOnDisplaysEnabled, Handler handler) {
    UserVisibilityMediator(boolean backgroundUsersOnDisplaysEnabled, Handler handler) {
        mVisibleBackgroundUsersEnabled = backgroundUsersOnDisplaysEnabled;
        mVisibleBackgroundUsersEnabled = backgroundUsersOnDisplaysEnabled;
        mUsersOnDisplaysMap = mVisibleBackgroundUsersEnabled ? new SparseIntArray() : null;
        if (mVisibleBackgroundUsersEnabled) {
            mUsersAssignedToDisplayOnStart = new SparseIntArray();
            mExtraDisplaysAssignedToUsers = new SparseIntArray();
        } else {
            mUsersAssignedToDisplayOnStart = null;
            mExtraDisplaysAssignedToUsers = null;
        }
        mHandler = handler;
        mHandler = handler;
        // TODO(b/242195409): might need to change this if boot logic is refactored for HSUM devices
        // 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);
        mStartedProfileGroupIds.put(INITIAL_CURRENT_USER_ID, INITIAL_CURRENT_USER_ID);
@@ -207,7 +225,7 @@ public final class UserVisibilityMediator implements Dumpable {
                    if (DBG) {
                    if (DBG) {
                        Slogf.d(TAG, "adding user / display mapping (%d -> %d)", userId, displayId);
                        Slogf.d(TAG, "adding user / display mapping (%d -> %d)", userId, displayId);
                    }
                    }
                    mUsersOnDisplaysMap.put(userId, displayId);
                    mUsersAssignedToDisplayOnStart.put(userId, displayId);
                    break;
                    break;
                case SECONDARY_DISPLAY_MAPPING_NOT_NEEDED:
                case SECONDARY_DISPLAY_MAPPING_NOT_NEEDED:
                    if (DBG) {
                    if (DBG) {
@@ -341,9 +359,9 @@ public final class UserVisibilityMediator implements Dumpable {
        }
        }


        // Check if display is available
        // Check if display is available
        for (int i = 0; i < mUsersOnDisplaysMap.size(); i++) {
        for (int i = 0; i < mUsersAssignedToDisplayOnStart.size(); i++) {
            int assignedUserId = mUsersOnDisplaysMap.keyAt(i);
            int assignedUserId = mUsersAssignedToDisplayOnStart.keyAt(i);
            int assignedDisplayId = mUsersOnDisplaysMap.valueAt(i);
            int assignedDisplayId = mUsersAssignedToDisplayOnStart.valueAt(i);
            if (DBG) {
            if (DBG) {
                Slogf.d(TAG, "%d: assignedUserId=%d, assignedDisplayId=%d",
                Slogf.d(TAG, "%d: assignedUserId=%d, assignedDisplayId=%d",
                        i, assignedUserId, assignedDisplayId);
                        i, assignedUserId, assignedDisplayId);
@@ -362,6 +380,100 @@ public final class UserVisibilityMediator implements Dumpable {
        return SECONDARY_DISPLAY_MAPPING_NEEDED;
        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)}.
     * See {@link UserManagerInternal#unassignUserFromDisplayOnStop(int)}.
     */
     */
@@ -373,7 +485,7 @@ public final class UserVisibilityMediator implements Dumpable {
        synchronized (mLock) {
        synchronized (mLock) {
            visibleUsersBefore = getVisibleUsers();
            visibleUsersBefore = getVisibleUsers();


            unassignUserFromDisplayOnStopLocked(userId);
            unassignUserFromAllDisplaysOnStopLocked(userId);


            visibleUsersAfter = getVisibleUsers();
            visibleUsersAfter = getVisibleUsers();
        }
        }
@@ -381,7 +493,7 @@ public final class UserVisibilityMediator implements Dumpable {
    }
    }


    @GuardedBy("mLock")
    @GuardedBy("mLock")
    private void unassignUserFromDisplayOnStopLocked(@UserIdInt int userId) {
    private void unassignUserFromAllDisplaysOnStopLocked(@UserIdInt int userId) {
        if (DBG) {
        if (DBG) {
            Slogf.d(TAG, "Removing %d from mStartedProfileGroupIds (%s)", userId,
            Slogf.d(TAG, "Removing %d from mStartedProfileGroupIds (%s)", userId,
                    mStartedProfileGroupIds);
                    mStartedProfileGroupIds);
@@ -395,10 +507,21 @@ public final class UserVisibilityMediator implements Dumpable {
            return;
            return;
        }
        }
        if (DBG) {
        if (DBG) {
            Slogf.d(TAG, "Removing %d from mUsersOnSecondaryDisplays (%s)", userId,
            Slogf.d(TAG, "Removing user %d from mUsersOnDisplaysMap (%s)", userId,
                    mUsersOnDisplaysMap);
                    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;
        boolean visible;
        synchronized (mLock) {
        synchronized (mLock) {
            visible = mUsersOnDisplaysMap.indexOfKey(userId) >= 0;
            visible = mUsersAssignedToDisplayOnStart.indexOfKey(userId) >= 0;
        }
        }
        if (DBG) {
        if (DBG) {
            Slogf.d(TAG, "isUserVisible(%d): %b from mapping", userId, visible);
            Slogf.d(TAG, "isUserVisible(%d): %b from mapping", userId, visible);
@@ -448,7 +571,12 @@ public final class UserVisibilityMediator implements Dumpable {
        }
        }


        synchronized (mLock) {
        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) {
        synchronized (mLock) {
            return mUsersOnDisplaysMap.get(userId, Display.INVALID_DISPLAY);
            return mUsersAssignedToDisplayOnStart.get(userId, Display.INVALID_DISPLAY);
        }
        }
    }
    }


    /**
    /**
     * See {@link UserManagerInternal#getUserAssignedToDisplay(int)}.
     * See {@link UserManagerInternal#getUserAssignedToDisplay(int)}.
     */
     */
    public int getUserAssignedToDisplay(@UserIdInt int displayId) {
    public @UserIdInt int getUserAssignedToDisplay(@UserIdInt int displayId) {
        if (displayId == Display.DEFAULT_DISPLAY || !mVisibleBackgroundUsersEnabled) {
        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();
            return getCurrentUserId();
        }
        }


        synchronized (mLock) {
        synchronized (mLock) {
            for (int i = 0; i < mUsersOnDisplaysMap.size(); i++) {
            for (int i = 0; i < mUsersAssignedToDisplayOnStart.size(); i++) {
                if (mUsersOnDisplaysMap.valueAt(i) != displayId) {
                if (mUsersAssignedToDisplayOnStart.valueAt(i) != displayId) {
                    continue;
                    continue;
                }
                }
                int userId = mUsersOnDisplaysMap.keyAt(i);
                int userId = mUsersAssignedToDisplayOnStart.keyAt(i);
                if (!isStartedProfile(userId)) {
                if (!isStartedProfile(userId)) {
                    return userId;
                    return userId;
                } else if (DBG) {
                } 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();
        int currentUserId = getCurrentUserId();
        if (DBG) {
        if (DBG) {
@@ -618,9 +763,11 @@ public final class UserVisibilityMediator implements Dumpable {
            ipw.print("Supports visible background users on displays: ");
            ipw.print("Supports visible background users on displays: ");
            ipw.println(mVisibleBackgroundUsersEnabled);
            ipw.println(mVisibleBackgroundUsersEnabled);


            if (mUsersOnDisplaysMap != null) {
            dumpSparseIntArray(ipw, mUsersAssignedToDisplayOnStart, "user / display", "u", "d");
                dumpSparseIntArray(ipw, mUsersOnDisplaysMap, "user / display", "u", "d");

            }
            dumpSparseIntArray(ipw, mExtraDisplaysAssignedToUsers, "extra display / user",
                    "d", "u");

            int numberListeners = mListeners.size();
            int numberListeners = mListeners.size();
            ipw.print("Number of listeners: ");
            ipw.print("Number of listeners: ");
            ipw.println(numberListeners);
            ipw.println(numberListeners);
@@ -638,8 +785,14 @@ public final class UserVisibilityMediator implements Dumpable {
        ipw.decreaseIndent();
        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) {
            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("Number of ");
        ipw.print(arrayDescription);
        ipw.print(arrayDescription);
        ipw.print(" mappings: ");
        ipw.print(" mappings: ");
+3 −0
Original line number Original line Diff line number Diff line
@@ -49,6 +49,7 @@ public final class UserVisibilityMediatorSUSDTest extends UserVisibilityMediator
        int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, FG,
        int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, FG,
                DEFAULT_DISPLAY);
                DEFAULT_DISPLAY);
        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
        expectUserCannotBeUnassignedFromDisplay(USER_ID, DEFAULT_DISPLAY);


        expectUserIsVisible(USER_ID);
        expectUserIsVisible(USER_ID);
        expectUserIsNotVisibleOnDisplay(USER_ID, INVALID_DISPLAY);
        expectUserIsNotVisibleOnDisplay(USER_ID, INVALID_DISPLAY);
@@ -80,6 +81,7 @@ public final class UserVisibilityMediatorSUSDTest extends UserVisibilityMediator
        int result = mMediator.assignUserToDisplayOnStart(currentUserId, currentUserId, FG,
        int result = mMediator.assignUserToDisplayOnStart(currentUserId, currentUserId, FG,
                DEFAULT_DISPLAY);
                DEFAULT_DISPLAY);
        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
        expectUserCannotBeUnassignedFromDisplay(currentUserId, DEFAULT_DISPLAY);


        expectUserIsVisible(currentUserId);
        expectUserIsVisible(currentUserId);
        expectUserIsNotVisibleOnDisplay(currentUserId, INVALID_DISPLAY);
        expectUserIsNotVisibleOnDisplay(currentUserId, INVALID_DISPLAY);
@@ -110,6 +112,7 @@ public final class UserVisibilityMediatorSUSDTest extends UserVisibilityMediator
        int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
        int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
                BG_VISIBLE, DEFAULT_DISPLAY);
                BG_VISIBLE, DEFAULT_DISPLAY);
        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
        expectUserCannotBeUnassignedFromDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY);


        expectUserIsVisible(PROFILE_USER_ID);
        expectUserIsVisible(PROFILE_USER_ID);
        expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, INVALID_DISPLAY);
        expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, INVALID_DISPLAY);
+95 −4
Original line number Original line Diff line number Diff line
@@ -165,12 +165,16 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
        expectNoDisplayAssignedToUser(USER_ID);
        expectNoDisplayAssignedToUser(USER_ID);
        expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY);
        expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY);


        assertInvisibleUserCannotBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID);

        listener.verify();
        listener.verify();
    }
    }


    @Test
    @Test
    public final void testStartVisibleBgUser_onDefaultDisplay() throws Exception {
    public final void testStartVisibleBgUser_onDefaultDisplay() throws Exception {
        visibleBgUserCannotBeStartedOnDefaultDisplayTest();
        visibleBgUserCannotBeStartedOnDefaultDisplayTest();

        assertInvisibleUserCannotBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID);
    }
    }


    protected final void visibleBgUserCannotBeStartedOnDefaultDisplayTest() throws Exception {
    protected final void visibleBgUserCannotBeStartedOnDefaultDisplayTest() throws Exception {
@@ -180,8 +184,8 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
                DEFAULT_DISPLAY);
                DEFAULT_DISPLAY);
        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);


        expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
        expectUserIsNotVisibleAtAll(USER_ID);
        expectNoDisplayAssignedToUser(PROFILE_USER_ID);
        expectNoDisplayAssignedToUser(USER_ID);


        listener.verify();
        listener.verify();
    }
    }
@@ -194,8 +198,11 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
                SECONDARY_DISPLAY_ID);
                SECONDARY_DISPLAY_ID);
        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);


        expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
        expectUserIsNotVisibleAtAll(USER_ID);
        expectNoDisplayAssignedToUser(PROFILE_USER_ID);
        expectNoDisplayAssignedToUser(USER_ID);

        assertInvisibleUserCannotBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID);
        assertInvisibleUserCannotBeAssignedExtraDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID);


        listener.verify();
        listener.verify();
    }
    }
@@ -217,6 +224,9 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
        expectNoDisplayAssignedToUser(USER_SYSTEM);
        expectNoDisplayAssignedToUser(USER_SYSTEM);
        expectUserAssignedToDisplay(SECONDARY_DISPLAY_ID, USER_ID);
        expectUserAssignedToDisplay(SECONDARY_DISPLAY_ID, USER_ID);


        assertUserCannotBeAssignedExtraDisplay(USER_SYSTEM, SECONDARY_DISPLAY_ID);
        assertUserCannotBeAssignedExtraDisplay(USER_SYSTEM, OTHER_SECONDARY_DISPLAY_ID);

        listener.verify();
        listener.verify();
    }
    }


@@ -256,6 +266,8 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
        expectNoDisplayAssignedToUser(PROFILE_USER_ID);
        expectNoDisplayAssignedToUser(PROFILE_USER_ID);
        expectUserAssignedToDisplay(DEFAULT_DISPLAY, OTHER_USER_ID);
        expectUserAssignedToDisplay(DEFAULT_DISPLAY, OTHER_USER_ID);


        assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);

        listener.verify();
        listener.verify();
    }
    }


@@ -289,6 +301,8 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
        expectNoDisplayAssignedToUser(PROFILE_USER_ID);
        expectNoDisplayAssignedToUser(PROFILE_USER_ID);
        expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY);
        expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY);


        assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);

        listener.verify();
        listener.verify();
    }
    }


@@ -305,6 +319,10 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
        expectNoDisplayAssignedToUser(PROFILE_USER_ID);
        expectNoDisplayAssignedToUser(PROFILE_USER_ID);
        expectInitialCurrentUserAssignedToDisplay(SECONDARY_DISPLAY_ID);
        expectInitialCurrentUserAssignedToDisplay(SECONDARY_DISPLAY_ID);


        assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
        assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID,
                OTHER_SECONDARY_DISPLAY_ID);

        listener.verify();
        listener.verify();
    }
    }


@@ -320,6 +338,10 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
        expectNoDisplayAssignedToUser(PROFILE_USER_ID);
        expectNoDisplayAssignedToUser(PROFILE_USER_ID);
        expectInitialCurrentUserAssignedToDisplay(SECONDARY_DISPLAY_ID);
        expectInitialCurrentUserAssignedToDisplay(SECONDARY_DISPLAY_ID);


        assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
        assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID,
                OTHER_SECONDARY_DISPLAY_ID);

        listener.verify();
        listener.verify();
    }
    }


@@ -336,6 +358,9 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
        expectNoDisplayAssignedToUser(PROFILE_USER_ID);
        expectNoDisplayAssignedToUser(PROFILE_USER_ID);
        expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY);
        expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY);


        assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY);
        assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);

        listener.verify();
        listener.verify();
    }
    }


@@ -351,6 +376,10 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
        expectNoDisplayAssignedToUser(PROFILE_USER_ID);
        expectNoDisplayAssignedToUser(PROFILE_USER_ID);
        expectInitialCurrentUserAssignedToDisplay(SECONDARY_DISPLAY_ID);
        expectInitialCurrentUserAssignedToDisplay(SECONDARY_DISPLAY_ID);


        assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
        assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID,
                OTHER_SECONDARY_DISPLAY_ID);

        listener.verify();
        listener.verify();
    }
    }


@@ -481,6 +510,63 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
                        .that(actualResult).isEqualTo(expectedResult);
                        .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) {
    protected void expectUserIsVisible(@UserIdInt int userId) {
        expectWithMessage("isUserVisible(%s)", userId)
        expectWithMessage("isUserVisible(%s)", userId)
                .that(mMediator.isUserVisible(userId))
                .that(mMediator.isUserVisible(userId))
@@ -534,6 +620,11 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
                .that(mMediator.getDisplayAssignedToUser(userId)).isEqualTo(INVALID_DISPLAY);
                .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) {
    protected void expectUserAssignedToDisplay(int displayId, @UserIdInt int userId) {
        expectWithMessage("getUserAssignedToDisplay(%s)", displayId)
        expectWithMessage("getUserAssignedToDisplay(%s)", displayId)
                .that(mMediator.getUserAssignedToDisplay(displayId)).isEqualTo(userId);
                .that(mMediator.getUserAssignedToDisplay(displayId)).isEqualTo(userId);
Loading