Loading core/java/android/content/pm/multiuser.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -615,3 +615,10 @@ flag { bug: "346553745" is_exported: true } flag { namespace: "multi_user" name: "logout_user_api" description: "Add API to logout user" bug: "350045389" } core/java/android/os/IUserManager.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -83,6 +83,8 @@ interface IUserManager { long getUserCreationTime(int userId); int getUserSwitchability(int userId); boolean isUserSwitcherEnabled(boolean showEvenIfNotActionable, int mUserId); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_USERS)") int getUserLogoutability(int userId); boolean isRestricted(int userId); boolean canHaveRestrictedProfile(int userId); boolean canAddPrivateProfile(int userId); Loading core/java/android/os/UserManager.java +68 −0 Original line number Diff line number Diff line Loading @@ -2260,6 +2260,45 @@ public class UserManager { }) public @interface UserSwitchabilityResult {} /** * Indicates that user can logout. * @hide */ public static final int LOGOUTABILITY_STATUS_OK = 0; /** * Indicates that user cannot logout because it is the system user. * @hide */ public static final int LOGOUTABILITY_STATUS_CANNOT_LOGOUT_SYSTEM_USER = 1; /** * Indicates that user cannot logout because there is no suitable user to logout to. This is * generally applicable to Headless System User Mode devices that do not have an interactive * system user. * @hide */ public static final int LOGOUTABILITY_STATUS_NO_SUITABLE_USER_TO_LOGOUT_TO = 2; /** * Indicates that user cannot logout because user switch cannot happen. * @hide */ public static final int LOGOUTABILITY_STATUS_CANNOT_SWITCH = 3; /** * Result returned in {@link #getUserLogoutability()} indicating user logoutability. * @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(flag = false, prefix = { "LOGOUTABILITY_STATUS_" }, value = { LOGOUTABILITY_STATUS_OK, LOGOUTABILITY_STATUS_CANNOT_LOGOUT_SYSTEM_USER, LOGOUTABILITY_STATUS_NO_SUITABLE_USER_TO_LOGOUT_TO, LOGOUTABILITY_STATUS_CANNOT_SWITCH }) public @interface UserLogoutability {} /** * A response code from {@link #removeUserWhenPossible(UserHandle, boolean)} indicating that * the specified user has been successfully removed. Loading Loading @@ -2736,6 +2775,35 @@ public class UserManager { } } /** * Returns whether logging out is currently allowed for the context user. * * <p>Logging out is not allowed in the following cases: * <ol> * <li>the user is system user * <li>there is no suitable user to logout to (if no interactive system user) * <li>the user is in a phone call * <li>{@link #DISALLOW_USER_SWITCH} is set * <li>system user hasn't been unlocked yet * </ol> * * @return A {@link UserLogoutability} flag indicating if the user can logout, * one of {@link #LOGOUTABILITY_STATUS_OK}, * {@link #LOGOUTABILITY_STATUS_CANNOT_LOGOUT_SYSTEM_USER}, * {@link #LOGOUTABILITY_STATUS_NO_SUITABLE_USER_TO_LOGOUT_TO}, * {@link #LOGOUTABILITY_STATUS_CANNOT_SWITCH}. * @hide */ @UserHandleAware @RequiresPermission(Manifest.permission.MANAGE_USERS) public @UserLogoutability int getUserLogoutability() { try { return mService.getUserLogoutability(mUserId); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } } /** * Returns the userId for the context user. * Loading services/core/java/com/android/server/pm/UserManagerService.java +50 −2 Original line number Diff line number Diff line Loading @@ -129,6 +129,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.UserManager.EnforcingUser; import android.os.UserManager.QuietModeFlag; import android.os.UserManager.UserLogoutability; import android.os.storage.StorageManager; import android.os.storage.StorageManagerInternal; import android.provider.Settings; Loading Loading @@ -1472,10 +1473,13 @@ public class UserManagerService extends IUserManager.Stub { return UserHandle.USER_NULL; } @Override public @CanBeNULL @UserIdInt int getPreviousFullUserToEnterForeground() { checkQueryOrCreateUsersPermission("get previous user"); return getPreviousFullUserToEnterForegroundUnchecked(); } private int getPreviousFullUserToEnterForegroundUnchecked() { int previousUser = UserHandle.USER_NULL; long latestEnteredTime = 0; final int currentUser = getCurrentUserId(); Loading Loading @@ -2915,7 +2919,8 @@ public class UserManagerService extends IUserManager.Stub { * @return A {@link UserManager.UserSwitchabilityResult} flag indicating if the user is * switchable. */ public @UserManager.UserSwitchabilityResult int getUserSwitchability(int userId) { @Override public @UserManager.UserSwitchabilityResult int getUserSwitchability(@UserIdInt int userId) { if (Flags.getUserSwitchabilityPermission()) { if (!hasManageUsersOrPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)) { throw new SecurityException( Loading Loading @@ -2993,6 +2998,49 @@ public class UserManagerService extends IUserManager.Stub { && multiUserSettingOn; } @Override public @UserLogoutability int getUserLogoutability(@UserIdInt int userId) { if (!android.multiuser.Flags.logoutUserApi()) { throw new UnsupportedOperationException( "aconfig flag android.multiuser.logout_user_api not enabled"); } checkManageUsersPermission("getUserLogoutability"); if (userId == UserHandle.USER_SYSTEM) { return UserManager.LOGOUTABILITY_STATUS_CANNOT_LOGOUT_SYSTEM_USER; } if (userId != getCurrentUserId()) { // TODO(b/393656514): Decide what to do with non-current/background users. // As of now, we are not going to logout a background user. A background user should // simply be stopped instead. return UserManager.LOGOUTABILITY_STATUS_CANNOT_SWITCH; } if (getUserSwitchability(userId) != UserManager.SWITCHABILITY_STATUS_OK) { return UserManager.LOGOUTABILITY_STATUS_CANNOT_SWITCH; } if (getUserToLogoutCurrentUserTo() == UserHandle.USER_NULL) { return UserManager.LOGOUTABILITY_STATUS_NO_SUITABLE_USER_TO_LOGOUT_TO; } return UserManager.LOGOUTABILITY_STATUS_OK; } /** * Returns the user to switch to, when logging out current user. If in HSUM and has interactive * system user, then logout would switch to the system user. Otherwise, logout would switch to * the previous foreground user. */ private @UserIdInt int getUserToLogoutCurrentUserTo() { if (isHeadlessSystemUserMode() && canSwitchToHeadlessSystemUser()) { return USER_SYSTEM; } return getPreviousFullUserToEnterForegroundUnchecked(); } @Override public boolean isUserSwitcherEnabled(boolean showEvenIfNotActionable, @UserIdInt int userId) { Loading services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java +86 −3 Original line number Diff line number Diff line Loading @@ -61,9 +61,12 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageManager; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.telecom.TelecomManager; import android.util.Log; import android.util.Pair; import android.util.SparseArray; Loading Loading @@ -166,6 +169,7 @@ public final class UserManagerServiceTest { private @Mock PackageManagerInternal mPackageManagerInternal; private @Mock KeyguardManager mKeyguardManager; private @Mock PowerManager mPowerManager; private @Mock TelecomManager mTelecomManager; /** * Reference to the {@link UserManagerService} being tested. Loading @@ -192,6 +196,7 @@ public final class UserManagerServiceTest { when(mSpiedContext.getSystemService(StorageManager.class)).thenReturn(mStorageManager); doReturn(mKeyguardManager).when(mSpiedContext).getSystemService(KeyguardManager.class); when(mSpiedContext.getSystemService(PowerManager.class)).thenReturn(mPowerManager); when(mSpiedContext.getSystemService(TelecomManager.class)).thenReturn(mTelecomManager); mockGetLocalService(LockSettingsInternal.class, mLockSettingsInternal); mockGetLocalService(PackageManagerInternal.class, mPackageManagerInternal); doNothing().when(mSpiedContext).sendBroadcastAsUser(any(), any(), any()); Loading Loading @@ -885,9 +890,7 @@ public final class UserManagerServiceTest { .getInteger(com.android.internal.R.integer.config_hsumBootStrategy); // Even if the headless system user switchable flag is true, the boot user should be the // first switchable full user. doReturn(true) .when(mSpyResources) .getBoolean(com.android.internal.R.bool.config_canSwitchToHeadlessSystemUser); mockCanSwitchToHeadlessSystemUser(true); assertThat(mUms.getBootUser()).isEqualTo(USER_ID); } Loading @@ -906,6 +909,75 @@ public final class UserManagerServiceTest { () -> mUms.getBootUser()); } @Test @EnableFlags(android.multiuser.Flags.FLAG_LOGOUT_USER_API) public void testGetUserLogoutability_HsumAndInteractiveHeadlessSystem_UserCanLogout() throws Exception { setSystemUserHeadless(true); addUser(USER_ID); setLastForegroundTime(USER_ID, 1_000_000L); mockCurrentUser(USER_ID); mockCanSwitchToHeadlessSystemUser(true); mockUserIsInCall(false); assertThat(mUms.getUserLogoutability(USER_ID)) .isEqualTo(UserManager.LOGOUTABILITY_STATUS_OK); } @Test @EnableFlags(android.multiuser.Flags.FLAG_LOGOUT_USER_API) public void testGetUserLogoutability_HsumAndNonInteractiveHeadlessSystem_UserCannotLogout() throws Exception { setSystemUserHeadless(true); mockCanSwitchToHeadlessSystemUser(false); addUser(USER_ID); setLastForegroundTime(USER_ID, 1_000_000L); mockCurrentUser(USER_ID); mockUserIsInCall(false); assertThat(mUms.getUserLogoutability(USER_ID)) .isEqualTo(UserManager.LOGOUTABILITY_STATUS_NO_SUITABLE_USER_TO_LOGOUT_TO); } @Test @EnableFlags(android.multiuser.Flags.FLAG_LOGOUT_USER_API) public void testGetUserLogoutability_Hsum_SystemUserCannotLogout() throws Exception { setSystemUserHeadless(true); mockCurrentUser(UserHandle.USER_SYSTEM); assertThat(mUms.getUserLogoutability(UserHandle.USER_SYSTEM)) .isEqualTo(UserManager.LOGOUTABILITY_STATUS_CANNOT_LOGOUT_SYSTEM_USER); } @Test @EnableFlags(android.multiuser.Flags.FLAG_LOGOUT_USER_API) public void testGetUserLogoutability_NonHsum_SystemUserCannotLogout() throws Exception { setSystemUserHeadless(false); mockCurrentUser(UserHandle.USER_SYSTEM); assertThat( mUms.getUserLogoutability(UserHandle.USER_SYSTEM)).isEqualTo( UserManager.LOGOUTABILITY_STATUS_CANNOT_LOGOUT_SYSTEM_USER); } @Test @EnableFlags(android.multiuser.Flags.FLAG_LOGOUT_USER_API) public void testGetUserLogoutability_CannotSwitch_CannotLogout() throws Exception { setSystemUserHeadless(true); addUser(USER_ID); addUser(OTHER_USER_ID); setLastForegroundTime(OTHER_USER_ID, 1_000_000L); mockCurrentUser(USER_ID); mUms.setUserRestriction(DISALLOW_USER_SWITCH, true, USER_ID); assertThat(mUms.getUserLogoutability(USER_ID)) .isEqualTo(UserManager.LOGOUTABILITY_STATUS_CANNOT_SWITCH); } @Test @DisableFlags(android.multiuser.Flags.FLAG_LOGOUT_USER_API) public void testGetUserLogoutability_LogoutDisabled() throws Exception { assertThrows(UnsupportedOperationException.class, () -> mUms.getUserLogoutability(USER_ID)); } /** * Returns true if the user's XML file has Default restrictions * @param userId Id of the user. Loading Loading @@ -1021,6 +1093,16 @@ public final class UserManagerServiceTest { doReturn(service).when(() -> LocalServices.getService(serviceClass)); } private void mockCanSwitchToHeadlessSystemUser(boolean canSwitch) { doReturn(canSwitch) .when(mSpyResources) .getBoolean(com.android.internal.R.bool.config_canSwitchToHeadlessSystemUser); } private void mockUserIsInCall(boolean isInCall) { when(mTelecomManager.isInCall()).thenReturn(isInCall); } private void addDefaultProfileAndParent() { addUser(PARENT_USER_ID); addProfile(PROFILE_USER_ID, PARENT_USER_ID); Loading Loading @@ -1063,6 +1145,7 @@ public final class UserManagerServiceTest { private void addUserData(TestUserData userData) { Log.d(TAG, "Adding " + userData); mUsers.put(userData.info.id, userData); mUms.putUserInfo(userData.info); } private void setSystemUserHeadless(boolean headless) { Loading Loading
core/java/android/content/pm/multiuser.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -615,3 +615,10 @@ flag { bug: "346553745" is_exported: true } flag { namespace: "multi_user" name: "logout_user_api" description: "Add API to logout user" bug: "350045389" }
core/java/android/os/IUserManager.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -83,6 +83,8 @@ interface IUserManager { long getUserCreationTime(int userId); int getUserSwitchability(int userId); boolean isUserSwitcherEnabled(boolean showEvenIfNotActionable, int mUserId); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_USERS)") int getUserLogoutability(int userId); boolean isRestricted(int userId); boolean canHaveRestrictedProfile(int userId); boolean canAddPrivateProfile(int userId); Loading
core/java/android/os/UserManager.java +68 −0 Original line number Diff line number Diff line Loading @@ -2260,6 +2260,45 @@ public class UserManager { }) public @interface UserSwitchabilityResult {} /** * Indicates that user can logout. * @hide */ public static final int LOGOUTABILITY_STATUS_OK = 0; /** * Indicates that user cannot logout because it is the system user. * @hide */ public static final int LOGOUTABILITY_STATUS_CANNOT_LOGOUT_SYSTEM_USER = 1; /** * Indicates that user cannot logout because there is no suitable user to logout to. This is * generally applicable to Headless System User Mode devices that do not have an interactive * system user. * @hide */ public static final int LOGOUTABILITY_STATUS_NO_SUITABLE_USER_TO_LOGOUT_TO = 2; /** * Indicates that user cannot logout because user switch cannot happen. * @hide */ public static final int LOGOUTABILITY_STATUS_CANNOT_SWITCH = 3; /** * Result returned in {@link #getUserLogoutability()} indicating user logoutability. * @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(flag = false, prefix = { "LOGOUTABILITY_STATUS_" }, value = { LOGOUTABILITY_STATUS_OK, LOGOUTABILITY_STATUS_CANNOT_LOGOUT_SYSTEM_USER, LOGOUTABILITY_STATUS_NO_SUITABLE_USER_TO_LOGOUT_TO, LOGOUTABILITY_STATUS_CANNOT_SWITCH }) public @interface UserLogoutability {} /** * A response code from {@link #removeUserWhenPossible(UserHandle, boolean)} indicating that * the specified user has been successfully removed. Loading Loading @@ -2736,6 +2775,35 @@ public class UserManager { } } /** * Returns whether logging out is currently allowed for the context user. * * <p>Logging out is not allowed in the following cases: * <ol> * <li>the user is system user * <li>there is no suitable user to logout to (if no interactive system user) * <li>the user is in a phone call * <li>{@link #DISALLOW_USER_SWITCH} is set * <li>system user hasn't been unlocked yet * </ol> * * @return A {@link UserLogoutability} flag indicating if the user can logout, * one of {@link #LOGOUTABILITY_STATUS_OK}, * {@link #LOGOUTABILITY_STATUS_CANNOT_LOGOUT_SYSTEM_USER}, * {@link #LOGOUTABILITY_STATUS_NO_SUITABLE_USER_TO_LOGOUT_TO}, * {@link #LOGOUTABILITY_STATUS_CANNOT_SWITCH}. * @hide */ @UserHandleAware @RequiresPermission(Manifest.permission.MANAGE_USERS) public @UserLogoutability int getUserLogoutability() { try { return mService.getUserLogoutability(mUserId); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } } /** * Returns the userId for the context user. * Loading
services/core/java/com/android/server/pm/UserManagerService.java +50 −2 Original line number Diff line number Diff line Loading @@ -129,6 +129,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.UserManager.EnforcingUser; import android.os.UserManager.QuietModeFlag; import android.os.UserManager.UserLogoutability; import android.os.storage.StorageManager; import android.os.storage.StorageManagerInternal; import android.provider.Settings; Loading Loading @@ -1472,10 +1473,13 @@ public class UserManagerService extends IUserManager.Stub { return UserHandle.USER_NULL; } @Override public @CanBeNULL @UserIdInt int getPreviousFullUserToEnterForeground() { checkQueryOrCreateUsersPermission("get previous user"); return getPreviousFullUserToEnterForegroundUnchecked(); } private int getPreviousFullUserToEnterForegroundUnchecked() { int previousUser = UserHandle.USER_NULL; long latestEnteredTime = 0; final int currentUser = getCurrentUserId(); Loading Loading @@ -2915,7 +2919,8 @@ public class UserManagerService extends IUserManager.Stub { * @return A {@link UserManager.UserSwitchabilityResult} flag indicating if the user is * switchable. */ public @UserManager.UserSwitchabilityResult int getUserSwitchability(int userId) { @Override public @UserManager.UserSwitchabilityResult int getUserSwitchability(@UserIdInt int userId) { if (Flags.getUserSwitchabilityPermission()) { if (!hasManageUsersOrPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)) { throw new SecurityException( Loading Loading @@ -2993,6 +2998,49 @@ public class UserManagerService extends IUserManager.Stub { && multiUserSettingOn; } @Override public @UserLogoutability int getUserLogoutability(@UserIdInt int userId) { if (!android.multiuser.Flags.logoutUserApi()) { throw new UnsupportedOperationException( "aconfig flag android.multiuser.logout_user_api not enabled"); } checkManageUsersPermission("getUserLogoutability"); if (userId == UserHandle.USER_SYSTEM) { return UserManager.LOGOUTABILITY_STATUS_CANNOT_LOGOUT_SYSTEM_USER; } if (userId != getCurrentUserId()) { // TODO(b/393656514): Decide what to do with non-current/background users. // As of now, we are not going to logout a background user. A background user should // simply be stopped instead. return UserManager.LOGOUTABILITY_STATUS_CANNOT_SWITCH; } if (getUserSwitchability(userId) != UserManager.SWITCHABILITY_STATUS_OK) { return UserManager.LOGOUTABILITY_STATUS_CANNOT_SWITCH; } if (getUserToLogoutCurrentUserTo() == UserHandle.USER_NULL) { return UserManager.LOGOUTABILITY_STATUS_NO_SUITABLE_USER_TO_LOGOUT_TO; } return UserManager.LOGOUTABILITY_STATUS_OK; } /** * Returns the user to switch to, when logging out current user. If in HSUM and has interactive * system user, then logout would switch to the system user. Otherwise, logout would switch to * the previous foreground user. */ private @UserIdInt int getUserToLogoutCurrentUserTo() { if (isHeadlessSystemUserMode() && canSwitchToHeadlessSystemUser()) { return USER_SYSTEM; } return getPreviousFullUserToEnterForegroundUnchecked(); } @Override public boolean isUserSwitcherEnabled(boolean showEvenIfNotActionable, @UserIdInt int userId) { Loading
services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java +86 −3 Original line number Diff line number Diff line Loading @@ -61,9 +61,12 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageManager; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.telecom.TelecomManager; import android.util.Log; import android.util.Pair; import android.util.SparseArray; Loading Loading @@ -166,6 +169,7 @@ public final class UserManagerServiceTest { private @Mock PackageManagerInternal mPackageManagerInternal; private @Mock KeyguardManager mKeyguardManager; private @Mock PowerManager mPowerManager; private @Mock TelecomManager mTelecomManager; /** * Reference to the {@link UserManagerService} being tested. Loading @@ -192,6 +196,7 @@ public final class UserManagerServiceTest { when(mSpiedContext.getSystemService(StorageManager.class)).thenReturn(mStorageManager); doReturn(mKeyguardManager).when(mSpiedContext).getSystemService(KeyguardManager.class); when(mSpiedContext.getSystemService(PowerManager.class)).thenReturn(mPowerManager); when(mSpiedContext.getSystemService(TelecomManager.class)).thenReturn(mTelecomManager); mockGetLocalService(LockSettingsInternal.class, mLockSettingsInternal); mockGetLocalService(PackageManagerInternal.class, mPackageManagerInternal); doNothing().when(mSpiedContext).sendBroadcastAsUser(any(), any(), any()); Loading Loading @@ -885,9 +890,7 @@ public final class UserManagerServiceTest { .getInteger(com.android.internal.R.integer.config_hsumBootStrategy); // Even if the headless system user switchable flag is true, the boot user should be the // first switchable full user. doReturn(true) .when(mSpyResources) .getBoolean(com.android.internal.R.bool.config_canSwitchToHeadlessSystemUser); mockCanSwitchToHeadlessSystemUser(true); assertThat(mUms.getBootUser()).isEqualTo(USER_ID); } Loading @@ -906,6 +909,75 @@ public final class UserManagerServiceTest { () -> mUms.getBootUser()); } @Test @EnableFlags(android.multiuser.Flags.FLAG_LOGOUT_USER_API) public void testGetUserLogoutability_HsumAndInteractiveHeadlessSystem_UserCanLogout() throws Exception { setSystemUserHeadless(true); addUser(USER_ID); setLastForegroundTime(USER_ID, 1_000_000L); mockCurrentUser(USER_ID); mockCanSwitchToHeadlessSystemUser(true); mockUserIsInCall(false); assertThat(mUms.getUserLogoutability(USER_ID)) .isEqualTo(UserManager.LOGOUTABILITY_STATUS_OK); } @Test @EnableFlags(android.multiuser.Flags.FLAG_LOGOUT_USER_API) public void testGetUserLogoutability_HsumAndNonInteractiveHeadlessSystem_UserCannotLogout() throws Exception { setSystemUserHeadless(true); mockCanSwitchToHeadlessSystemUser(false); addUser(USER_ID); setLastForegroundTime(USER_ID, 1_000_000L); mockCurrentUser(USER_ID); mockUserIsInCall(false); assertThat(mUms.getUserLogoutability(USER_ID)) .isEqualTo(UserManager.LOGOUTABILITY_STATUS_NO_SUITABLE_USER_TO_LOGOUT_TO); } @Test @EnableFlags(android.multiuser.Flags.FLAG_LOGOUT_USER_API) public void testGetUserLogoutability_Hsum_SystemUserCannotLogout() throws Exception { setSystemUserHeadless(true); mockCurrentUser(UserHandle.USER_SYSTEM); assertThat(mUms.getUserLogoutability(UserHandle.USER_SYSTEM)) .isEqualTo(UserManager.LOGOUTABILITY_STATUS_CANNOT_LOGOUT_SYSTEM_USER); } @Test @EnableFlags(android.multiuser.Flags.FLAG_LOGOUT_USER_API) public void testGetUserLogoutability_NonHsum_SystemUserCannotLogout() throws Exception { setSystemUserHeadless(false); mockCurrentUser(UserHandle.USER_SYSTEM); assertThat( mUms.getUserLogoutability(UserHandle.USER_SYSTEM)).isEqualTo( UserManager.LOGOUTABILITY_STATUS_CANNOT_LOGOUT_SYSTEM_USER); } @Test @EnableFlags(android.multiuser.Flags.FLAG_LOGOUT_USER_API) public void testGetUserLogoutability_CannotSwitch_CannotLogout() throws Exception { setSystemUserHeadless(true); addUser(USER_ID); addUser(OTHER_USER_ID); setLastForegroundTime(OTHER_USER_ID, 1_000_000L); mockCurrentUser(USER_ID); mUms.setUserRestriction(DISALLOW_USER_SWITCH, true, USER_ID); assertThat(mUms.getUserLogoutability(USER_ID)) .isEqualTo(UserManager.LOGOUTABILITY_STATUS_CANNOT_SWITCH); } @Test @DisableFlags(android.multiuser.Flags.FLAG_LOGOUT_USER_API) public void testGetUserLogoutability_LogoutDisabled() throws Exception { assertThrows(UnsupportedOperationException.class, () -> mUms.getUserLogoutability(USER_ID)); } /** * Returns true if the user's XML file has Default restrictions * @param userId Id of the user. Loading Loading @@ -1021,6 +1093,16 @@ public final class UserManagerServiceTest { doReturn(service).when(() -> LocalServices.getService(serviceClass)); } private void mockCanSwitchToHeadlessSystemUser(boolean canSwitch) { doReturn(canSwitch) .when(mSpyResources) .getBoolean(com.android.internal.R.bool.config_canSwitchToHeadlessSystemUser); } private void mockUserIsInCall(boolean isInCall) { when(mTelecomManager.isInCall()).thenReturn(isInCall); } private void addDefaultProfileAndParent() { addUser(PARENT_USER_ID); addProfile(PROFILE_USER_ID, PARENT_USER_ID); Loading Loading @@ -1063,6 +1145,7 @@ public final class UserManagerServiceTest { private void addUserData(TestUserData userData) { Log.d(TAG, "Adding " + userData); mUsers.put(userData.info.id, userData); mUms.putUserInfo(userData.info); } private void setSystemUserHeadless(boolean headless) { Loading