diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 3d5139b0d6d5b..797cca86e055f 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -10221,7 +10221,7 @@ package android.os { method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) public android.graphics.Bitmap getUserIcon(); method @Deprecated @android.os.UserManager.UserRestrictionSource @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS}) public int getUserRestrictionSource(String, android.os.UserHandle); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS}) public java.util.List getUserRestrictionSources(String, android.os.UserHandle); - method @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public int getUserSwitchability(); + method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public int getUserSwitchability(); method @NonNull @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.MANAGE_USERS"}) public java.util.Set getVisibleUsers(); method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean hasRestrictedProfiles(); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean hasUserRestrictionForUser(@NonNull String, @NonNull android.os.UserHandle); diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index d31540a65f2f3..c2ddf4535d915 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -79,6 +79,7 @@ interface IUserManager { String getUserAccount(int userId); void setUserAccount(int userId, String accountName); long getUserCreationTime(int userId); + int getUserSwitchability(int userId); boolean isUserSwitcherEnabled(boolean showEvenIfNotActionable, int mUserId); boolean isRestricted(int userId); boolean canHaveRestrictedProfile(int userId); diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 07c4b441655ee..5f2f710e3c015 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -59,7 +59,6 @@ import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.location.LocationManager; import android.provider.Settings; -import android.telecom.TelecomManager; import android.util.AndroidException; import android.util.ArraySet; import android.util.Log; @@ -1748,7 +1747,7 @@ public class UserManager { public static final int SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED = 1 << 2; /** - * Result returned in {@link #getUserSwitchability()} indicating user swichability. + * Result returned in {@link #getUserSwitchability()} indicating user switchability. * @hide */ @Retention(RetentionPolicy.SOURCE) @@ -2128,20 +2127,16 @@ public class UserManager { * @hide */ @Deprecated - @RequiresPermission(allOf = { - Manifest.permission.READ_PHONE_STATE, - Manifest.permission.MANAGE_USERS}, // Can be INTERACT_ACROSS_USERS instead. - conditional = true) + @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, + android.Manifest.permission.INTERACT_ACROSS_USERS}) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @UserHandleAware public boolean canSwitchUsers() { - boolean allowUserSwitchingWhenSystemUserLocked = Settings.Global.getInt( - mContext.getContentResolver(), - Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED, 0) != 0; - boolean isSystemUserUnlocked = isUserUnlocked(UserHandle.SYSTEM); - boolean isUserSwitchDisallowed = hasUserRestrictionForUser(DISALLOW_USER_SWITCH, mUserId); - return (allowUserSwitchingWhenSystemUserLocked || isSystemUserUnlocked) && !inCall() - && !isUserSwitchDisallowed; + try { + return mService.getUserSwitchability(mUserId) == SWITCHABILITY_STATUS_OK; + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } } /** @@ -2156,9 +2151,8 @@ public class UserManager { * @hide */ @SystemApi - @RequiresPermission(allOf = {Manifest.permission.READ_PHONE_STATE, - android.Manifest.permission.MANAGE_USERS, - android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true) + @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, + android.Manifest.permission.INTERACT_ACROSS_USERS}) @UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.TIRAMISU) public @UserSwitchabilityResult int getUserSwitchability() { return getUserSwitchability(UserHandle.of(getContextUserIfAppropriate())); @@ -2175,31 +2169,14 @@ public class UserManager { * @return A {@link UserSwitchabilityResult} flag indicating if the user is switchable. * @hide */ - @RequiresPermission(allOf = {Manifest.permission.READ_PHONE_STATE, - android.Manifest.permission.MANAGE_USERS, - android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true) + @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, + android.Manifest.permission.INTERACT_ACROSS_USERS}) public @UserSwitchabilityResult int getUserSwitchability(UserHandle userHandle) { - int flags = SWITCHABILITY_STATUS_OK; - if (inCall()) { - flags |= SWITCHABILITY_STATUS_USER_IN_CALL; + try { + return mService.getUserSwitchability(userHandle.getIdentifier()); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); } - if (hasUserRestrictionForUser(DISALLOW_USER_SWITCH, userHandle)) { - flags |= SWITCHABILITY_STATUS_USER_SWITCH_DISALLOWED; - } - - // System User is always unlocked in Headless System User Mode, so ignore this flag - if (!isHeadlessSystemUserMode()) { - final boolean allowUserSwitchingWhenSystemUserLocked = Settings.Global.getInt( - mContext.getContentResolver(), - Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED, 0) != 0; - final boolean systemUserUnlocked = isUserUnlocked(UserHandle.SYSTEM); - - if (!allowUserSwitchingWhenSystemUserLocked && !systemUserUnlocked) { - flags |= SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED; - } - } - - return flags; } /** @@ -5614,11 +5591,6 @@ public class UserManager { } } - private boolean inCall() { - final TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class); - return telecomManager != null && telecomManager.isInCall(); - } - /* Cache key for anything that assumes that userIds cannot be re-used without rebooting. */ private static final String CACHE_KEY_STATIC_USER_PROPERTIES = "cache_key.static_user_props"; diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 3234e87a71257..7191daa76186e 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -93,6 +93,7 @@ import android.os.storage.StorageManagerInternal; import android.provider.Settings; import android.service.voice.VoiceInteractionManagerInternal; import android.stats.devicepolicy.DevicePolicyEnums; +import android.telecom.TelecomManager; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -128,7 +129,6 @@ import com.android.server.SystemService; import com.android.server.am.UserState; import com.android.server.pm.UserManagerInternal.UserLifecycleListener; import com.android.server.pm.UserManagerInternal.UserRestrictionsListener; -import com.android.server.pm.UserManagerInternal.UserVisibilityListener; import com.android.server.storage.DeviceStorageMonitorInternal; import com.android.server.utils.Slogf; import com.android.server.utils.TimingsTraceAndSlog; @@ -1970,6 +1970,63 @@ public class UserManagerService extends IUserManager.Stub { } } + /** + * Returns whether switching users is currently allowed for the provided user. + *

+ * Switching users is not allowed in the following cases: + *

  • the user is in a phone call
  • + *
  • {@link UserManager#DISALLOW_USER_SWITCH} is set
  • + *
  • system user hasn't been unlocked yet
  • + * + * @return A {@link UserManager.UserSwitchabilityResult} flag indicating if the user is + * switchable. + */ + public @UserManager.UserSwitchabilityResult int getUserSwitchability(int userId) { + checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId, "getUserSwitchability"); + + final TimingsTraceAndSlog t = new TimingsTraceAndSlog(); + t.traceBegin("getUserSwitchability-" + userId); + + int flags = UserManager.SWITCHABILITY_STATUS_OK; + + t.traceBegin("TM.isInCall"); + final long identity = Binder.clearCallingIdentity(); + try { + final TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class); + if (telecomManager != null && telecomManager.isInCall()) { + flags |= UserManager.SWITCHABILITY_STATUS_USER_IN_CALL; + } + } finally { + Binder.restoreCallingIdentity(identity); + } + t.traceEnd(); + + t.traceBegin("hasUserRestriction-DISALLOW_USER_SWITCH"); + if (mLocalService.hasUserRestriction(DISALLOW_USER_SWITCH, userId)) { + flags |= UserManager.SWITCHABILITY_STATUS_USER_SWITCH_DISALLOWED; + } + t.traceEnd(); + + // System User is always unlocked in Headless System User Mode, so ignore this flag + if (!isHeadlessSystemUserMode()) { + t.traceBegin("getInt-ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED"); + final boolean allowUserSwitchingWhenSystemUserLocked = Settings.Global.getInt( + mContext.getContentResolver(), + Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED, 0) != 0; + t.traceEnd(); + t.traceBegin("isUserUnlocked-USER_SYSTEM"); + final boolean systemUserUnlocked = mLocalService.isUserUnlocked(UserHandle.USER_SYSTEM); + t.traceEnd(); + + if (!allowUserSwitchingWhenSystemUserLocked && !systemUserUnlocked) { + flags |= UserManager.SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED; + } + } + t.traceEnd(); + + return flags; + } + @VisibleForTesting boolean isUserSwitcherEnabled(@UserIdInt int mUserId) { boolean multiUserSettingOn = Settings.Global.getInt(mContext.getContentResolver(),