diff --git a/api/current.txt b/api/current.txt index d9a89b1982a81..c4510651fd5a2 100644 --- a/api/current.txt +++ b/api/current.txt @@ -36506,10 +36506,10 @@ package android.os { method public static android.content.Intent createUserCreationIntent(@Nullable String, @Nullable String, @Nullable String, @Nullable android.os.PersistableBundle); method @WorkerThread public android.os.Bundle getApplicationRestrictions(String); method public long getSerialNumberForUser(android.os.UserHandle); - method public int getUserCount(); + method @RequiresPermission("android.permission.MANAGE_USERS") public int getUserCount(); method public long getUserCreationTime(android.os.UserHandle); method public android.os.UserHandle getUserForSerialNumber(long); - method public String getUserName(); + method @NonNull @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}, conditional=true) public String getUserName(); method public java.util.List getUserProfiles(); method public android.os.Bundle getUserRestrictions(); method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.INTERACT_ACROSS_USERS"}, conditional=true) public android.os.Bundle getUserRestrictions(android.os.UserHandle); @@ -36519,14 +36519,14 @@ package android.os { method public boolean isQuietModeEnabled(android.os.UserHandle); method public boolean isSystemUser(); method public boolean isUserAGoat(); - method public boolean isUserRunning(android.os.UserHandle); - method public boolean isUserRunningOrStopping(android.os.UserHandle); + method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.INTERACT_ACROSS_USERS"}, conditional=true) public boolean isUserRunning(android.os.UserHandle); + method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.INTERACT_ACROSS_USERS"}, conditional=true) public boolean isUserRunningOrStopping(android.os.UserHandle); method public boolean isUserUnlocked(); - method public boolean isUserUnlocked(android.os.UserHandle); - method public boolean requestQuietModeEnabled(boolean, @NonNull android.os.UserHandle); + method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.INTERACT_ACROSS_USERS"}, conditional=true) public boolean isUserUnlocked(android.os.UserHandle); + method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.MODIFY_QUIET_MODE"}, conditional=true) public boolean requestQuietModeEnabled(boolean, @NonNull android.os.UserHandle); method public boolean requestQuietModeEnabled(boolean, @NonNull android.os.UserHandle, int); method @Deprecated public boolean setRestrictionsChallenge(String); - method @Deprecated public void setUserRestriction(String, boolean); + method @Deprecated @RequiresPermission("android.permission.MANAGE_USERS") public void setUserRestriction(String, boolean); method @Deprecated public void setUserRestrictions(android.os.Bundle); method @Deprecated public void setUserRestrictions(android.os.Bundle, android.os.UserHandle); method public static boolean supportsMultipleUsers(); diff --git a/api/system-current.txt b/api/system-current.txt index 3c9f941582a3d..e5cc384217083 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -67,6 +67,7 @@ package android { field public static final String CONTROL_INCALL_EXPERIENCE = "android.permission.CONTROL_INCALL_EXPERIENCE"; field public static final String CONTROL_KEYGUARD_SECURE_NOTIFICATIONS = "android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS"; field public static final String CONTROL_VPN = "android.permission.CONTROL_VPN"; + field public static final String CREATE_USERS = "android.permission.CREATE_USERS"; field public static final String CRYPT_KEEPER = "android.permission.CRYPT_KEEPER"; field public static final String DEVICE_POWER = "android.permission.DEVICE_POWER"; field public static final String DISPATCH_PROVISIONING_MESSAGE = "android.permission.DISPATCH_PROVISIONING_MESSAGE"; @@ -327,7 +328,7 @@ package android.app { method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getPackageImportance(String); method @NonNull public java.util.Collection getSupportedLocales(); method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getUidImportance(int); - method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, "android.permission.CREATE_USERS"}) public boolean isProfileForeground(@NonNull android.os.UserHandle); + method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean isProfileForeground(@NonNull android.os.UserHandle); method @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) public void killProcessesWhenImperceptible(@NonNull int[], @NonNull String); method @RequiresPermission(android.Manifest.permission.KILL_UID) public void killUid(int, String); method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener); @@ -8015,6 +8016,7 @@ package android.os { public class UserManager { method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void clearSeedAccountData(); + method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.os.UserHandle createProfile(@NonNull String, @NonNull String, @Nullable String[]) throws android.os.UserManager.UserOperationException; method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.UserHandle getProfileParent(@NonNull android.os.UserHandle); method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getSeedAccountName(); method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.PersistableBundle getSeedAccountOptions(); @@ -8022,22 +8024,26 @@ package android.os { method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public long[] getSerialNumbersOfUsers(boolean); method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List getUserHandles(boolean); method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) public android.graphics.Bitmap getUserIcon(); + method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public java.util.List getUserProfiles(boolean); method @Deprecated @android.os.UserManager.UserRestrictionSource @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public int getUserRestrictionSource(String, android.os.UserHandle); method @RequiresPermission(android.Manifest.permission.MANAGE_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 public boolean hasRestrictedProfiles(); + 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); method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isAdminUser(); - method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isGuestUser(); - method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isManagedProfile(int); - method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isPrimaryUser(); + method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean isGuestUser(); + method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isManagedProfile(int); + method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean isPrimaryUser(); + method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isProfile(); method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isRestrictedProfile(); - method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isRestrictedProfile(@NonNull android.os.UserHandle); + method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean isRestrictedProfile(@NonNull android.os.UserHandle); method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isSameProfileGroup(@NonNull android.os.UserHandle, @NonNull android.os.UserHandle); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) public boolean isUserNameSet(); - method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public boolean isUserUnlockingOrUnlocked(@NonNull android.os.UserHandle); - method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean removeUser(@NonNull android.os.UserHandle); - method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserIcon(@NonNull android.graphics.Bitmap); + method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isUserOfType(@NonNull String); + method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isUserOfType(@NonNull android.os.UserHandle, @NonNull String); + method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isUserUnlockingOrUnlocked(@NonNull android.os.UserHandle); + method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean removeUser(@NonNull android.os.UserHandle); + method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserIcon(@NonNull android.graphics.Bitmap) throws android.os.UserManager.UserOperationException; method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserName(@Nullable String); field public static final String ACTION_USER_RESTRICTIONS_CHANGED = "android.os.action.USER_RESTRICTIONS_CHANGED"; field @Deprecated public static final String DISALLOW_OEM_UNLOCK = "no_oem_unlock"; @@ -8050,6 +8056,10 @@ package android.os { field public static final int SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED = 4; // 0x4 field public static final int SWITCHABILITY_STATUS_USER_IN_CALL = 1; // 0x1 field public static final int SWITCHABILITY_STATUS_USER_SWITCH_DISALLOWED = 2; // 0x2 + field public static final String USER_TYPE_FULL_SECONDARY = "android.os.usertype.full.SECONDARY"; + field public static final String USER_TYPE_FULL_SYSTEM = "android.os.usertype.full.SYSTEM"; + field public static final String USER_TYPE_PROFILE_MANAGED = "android.os.usertype.profile.MANAGED"; + field public static final String USER_TYPE_SYSTEM_HEADLESS = "android.os.usertype.system.HEADLESS"; } public static final class UserManager.EnforcingUser implements android.os.Parcelable { diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index 33d613152bc1e..b10abe7557d59 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -41,11 +41,11 @@ interface IUserManager { * END OF DO NOT MOVE */ - UserInfo createUser(in String name, in String userType, int flags); - UserInfo preCreateUser(in String userType); - UserInfo createProfileForUser(in String name, in String userType, int flags, int userId, + UserInfo createUserWithThrow(in String name, in String userType, int flags); + UserInfo preCreateUserWithThrow(in String userType); + UserInfo createProfileForUserWithThrow(in String name, in String userType, int flags, int userId, in String[] disallowedPackages); - UserInfo createRestrictedProfile(String name, int parentUserHandle); + UserInfo createRestrictedProfileWithThrow(String name, int parentUserHandle); void setUserEnabled(int userId); void setUserAdmin(int userId); void evictCredentialEncryptionKey(int userId); @@ -100,7 +100,7 @@ interface IUserManager { boolean isManagedProfile(int userId); boolean isDemoUser(int userId); boolean isPreCreated(int userId); - UserInfo createProfileForUserEvenWhenDisallowed(in String name, in String userType, int flags, + UserInfo createProfileForUserEvenWhenDisallowedWithThrow(in String name, in String userType, int flags, int userId, in String[] disallowedPackages); boolean isUserUnlockingOrUnlocked(int userId); int getUserIconBadgeResId(int userId); diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 12e843c874813..08e4c3ae36834 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -28,6 +28,7 @@ import android.annotation.StringDef; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; +import android.annotation.UserHandleAware; import android.annotation.UserIdInt; import android.annotation.WorkerThread; import android.app.Activity; @@ -50,6 +51,7 @@ import android.graphics.drawable.Drawable; import android.location.LocationManager; import android.provider.Settings; import android.telephony.TelephonyManager; +import android.util.AndroidException; import android.view.WindowManager.LayoutParams; import com.android.internal.R; @@ -77,8 +79,12 @@ public class UserManager { private static final String TAG = "UserManager"; @UnsupportedAppUsage private final IUserManager mService; + /** Holding the Application context (not constructor param context). */ private final Context mContext; + /** The userId of the constructor param context. To be used instead of mContext.getUserId(). */ + private final @UserIdInt int mUserId; + private Boolean mIsManagedProfileCached; private Boolean mIsProfileCached; @@ -87,6 +93,7 @@ public class UserManager { * This type of user cannot be created; it can only pre-exist on first boot. * @hide */ + @SystemApi public static final String USER_TYPE_FULL_SYSTEM = "android.os.usertype.full.SYSTEM"; /** @@ -95,6 +102,7 @@ public class UserManager { * This is sometimes called an ordinary 'secondary user'. * @hide */ + @SystemApi public static final String USER_TYPE_FULL_SECONDARY = "android.os.usertype.full.SECONDARY"; /** @@ -122,6 +130,7 @@ public class UserManager { * The intended purpose is for work profiles, which are managed by a corporate entity. * @hide */ + @SystemApi public static final String USER_TYPE_PROFILE_MANAGED = "android.os.usertype.profile.MANAGED"; /** @@ -130,6 +139,7 @@ public class UserManager { * This type of user cannot be created; it can only pre-exist on first boot. * @hide */ + @SystemApi public static final String USER_TYPE_SYSTEM_HEADLESS = "android.os.usertype.system.HEADLESS"; /** @@ -1435,6 +1445,62 @@ public class UserManager { public @UserOperationResult int getUserOperationResult() { return mUserOperationResult; } + + /** + * Returns a UserOperationException containing the same message and error code. + * @hide + */ + public static UserOperationException from(ServiceSpecificException exception) { + return new UserOperationException(exception.getMessage(), exception.errorCode); + } + } + + /** + * Converts the ServiceSpecificException into a UserOperationException or throws null; + * + * @param exception exception to convert. + * @param throwInsteadOfNull if an exception should be thrown or null returned. + * @return null if chosen not to throw exception. + * @throws UserOperationException + */ + private T returnNullOrThrowUserOperationException(ServiceSpecificException exception, + boolean throwInsteadOfNull) throws UserOperationException { + if (throwInsteadOfNull) { + throw UserOperationException.from(exception); + } else { + return null; + } + } + + /** + * Thrown to indicate user operation failed. (Checked exception) + * @hide + */ + public static class CheckedUserOperationException extends AndroidException { + private final @UserOperationResult int mUserOperationResult; + + /** + * Constructs a CheckedUserOperationException with specific result code. + * + * @param message the detail message + * @param userOperationResult the result code + * @hide + */ + public CheckedUserOperationException(String message, + @UserOperationResult int userOperationResult) { + super(message); + mUserOperationResult = userOperationResult; + } + + /** Returns the operation result code. */ + public @UserOperationResult int getUserOperationResult() { + return mUserOperationResult; + } + + /** Return a ServiceSpecificException containing the same message and error code. */ + public ServiceSpecificException toServiceSpecificException() { + return new ServiceSpecificException(mUserOperationResult, getMessage()); + } } /** @hide */ @@ -1447,6 +1513,7 @@ public class UserManager { public UserManager(Context context, IUserManager service) { mService = service; mContext = context.getApplicationContext(); + mUserId = context.getUserId(); } /** @@ -1586,17 +1653,25 @@ public class UserManager { } /** - * Returns the user name of the user making this call. This call is only - * available to applications on the system image; it requires the - * {@code android.permission.MANAGE_USERS} or {@code android.permission.GET_ACCOUNTS_PRIVILEGED} - * permissions. + * Returns the user name of the context user. This call is only available to applications on + * the system image; it requires the {@code android.permission.MANAGE_USERS} or {@code + * android.permission.GET_ACCOUNTS_PRIVILEGED} permissions. + * * @return the user name */ - public String getUserName() { - try { - return mService.getUserName(); - } catch (RemoteException re) { - throw re.rethrowFromSystemServer(); + @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, + android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}, conditional = true) + @UserHandleAware + public @NonNull String getUserName() { + if (UserHandle.myUserId() == mUserId) { + try { + return mService.getUserName(); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } else { + UserInfo userInfo = getUserInfo(mUserId); + return userInfo == null ? "" : userInfo.name; } } @@ -1639,7 +1714,8 @@ public class UserManager { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.MANAGE_USERS) + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}) public boolean isPrimaryUser() { UserInfo user = getUserInfo(UserHandle.myUserId()); return user != null && user.isPrimary(); @@ -1676,22 +1752,26 @@ public class UserManager { * user. */ @UnsupportedAppUsage + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}) public boolean isUserAdmin(@UserIdInt int userId) { UserInfo user = getUserInfo(userId); return user != null && user.isAdmin(); } /** - * Returns whether the current user is of the given user type, such as + * Returns whether the context user's user is of the given user type, such as * {@link UserManager#USER_TYPE_FULL_GUEST}. * * @return true if the user is of the given user type. * @hide */ + @SystemApi + @UserHandleAware @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isUserOfType(@NonNull String userType) { try { - return mService.isUserOfType(UserHandle.myUserId(), userType); + return mService.isUserOfType(mUserId, userType); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } @@ -1707,6 +1787,7 @@ public class UserManager { * @return true if the userHandle user is of type userType * @hide */ + @SystemApi @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isUserOfType(@NonNull UserHandle userHandle, @NonNull String userType) { try { @@ -1786,7 +1867,8 @@ public class UserManager { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.MANAGE_USERS) + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}) public boolean isRestrictedProfile(@NonNull UserHandle user) { try { return mService.getUserInfo(user.getIdentifier()).isRestricted(); @@ -1799,6 +1881,7 @@ public class UserManager { * Checks if specified user can have restricted profile. * @hide */ + @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean canHaveRestrictedProfile(@UserIdInt int userId) { try { return mService.canHaveRestrictedProfile(userId); @@ -1813,6 +1896,7 @@ public class UserManager { * @hide */ @SystemApi + @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean hasRestrictedProfiles() { try { return mService.hasRestrictedProfiles(); @@ -1827,6 +1911,8 @@ public class UserManager { * @hide */ @UnsupportedAppUsage + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}) public boolean isGuestUser(@UserIdInt int userId) { UserInfo user = getUserInfo(userId); return user != null && user.isGuest(); @@ -1839,7 +1925,8 @@ public class UserManager { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.MANAGE_USERS) + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}) public boolean isGuestUser() { UserInfo user = getUserInfo(UserHandle.myUserId()); return user != null && user.isGuest(); @@ -1861,47 +1948,45 @@ public class UserManager { } /** - * Checks if the calling app is running in a profile. + * Checks if the calling context user is running in a profile. + * + * Requires {@link android.Manifest.permission#MANAGE_USERS} or + * {@link android.Manifest.permission#INTERACT_ACROSS_USERS} permission, otherwise the + * caller must be in the same profile group of specified user. * * @return whether the caller is in a profile. * @hide */ + @SystemApi + @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, + android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true) + @UserHandleAware public boolean isProfile() { - // No need for synchronization. Once it becomes non-null, it'll be non-null forever. - // Worst case we might end up calling the AIDL method multiple times but that's fine. - if (mIsProfileCached != null) { - return mIsProfileCached; - } - try { - mIsProfileCached = mService.isProfile(UserHandle.myUserId()); - return mIsProfileCached; - } catch (RemoteException re) { - throw re.rethrowFromSystemServer(); + return isProfile(mUserId); + } + + private boolean isProfile(@UserIdInt int userId) { + if (userId == UserHandle.myUserId()) { + // No need for synchronization. Once it becomes non-null, it'll be non-null forever. + // Worst case we might end up calling the AIDL method multiple times but that's fine. + if (mIsProfileCached != null) { + return mIsProfileCached; + } + try { + mIsProfileCached = mService.isProfile(userId); + return mIsProfileCached; + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } else { + try { + return mService.isProfile(userId); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } } } - /** - * Checks if the specified user is a profile. - * - * Requires {@link android.Manifest.permission#MANAGE_USERS} or - * {@link android.Manifest.permission#INTERACT_ACROSS_USERS} permission, otherwise the caller - * must be in the same profile group of specified user. - * - * @return whether the specified user is a profile. - * @hide - */ - @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, - android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true) - public boolean isProfile(@UserIdInt int userId) { - if (userId == UserHandle.myUserId()) { - return isProfile(); - } - try { - return mService.isProfile(userId); - } catch (RemoteException re) { - throw re.rethrowFromSystemServer(); - } - } /** * Checks if the calling app is running in a managed profile. * @@ -1931,7 +2016,8 @@ public class UserManager { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.MANAGE_USERS) + @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, + Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true) public boolean isManagedProfile(@UserIdInt int userId) { if (userId == UserHandle.myUserId()) { return isManagedProfile(); @@ -1949,6 +2035,8 @@ public class UserManager { * @return whether the caller is an ephemeral user. * @hide */ + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}) public boolean isEphemeralUser() { return isUserEphemeral(UserHandle.myUserId()); } @@ -1957,6 +2045,8 @@ public class UserManager { * Returns whether the specified user is ephemeral. * @hide */ + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}) public boolean isUserEphemeral(@UserIdInt int userId) { final UserInfo user = getUserInfo(userId); return user != null && user.isEphemeral(); @@ -1978,12 +2068,15 @@ public class UserManager { * * @param user The user to retrieve the running state for. */ - // Note this requires either INTERACT_ACROSS_USERS or MANAGE_USERS. + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true) public boolean isUserRunning(UserHandle user) { return isUserRunning(user.getIdentifier()); } /** {@hide} */ + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true) public boolean isUserRunning(@UserIdInt int userId) { try { return mService.isUserRunning(userId); @@ -2007,7 +2100,8 @@ public class UserManager { * * @param user The user to retrieve the running state for. */ - // Note this requires either INTERACT_ACROSS_USERS or MANAGE_USERS. + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true) public boolean isUserRunningOrStopping(UserHandle user) { try { // TODO: reconcile stopped vs stopping? @@ -2054,12 +2148,16 @@ public class UserManager { * @see Intent#ACTION_USER_UNLOCKED * @see Context#createDeviceProtectedStorageContext() */ + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true) public boolean isUserUnlocked(UserHandle user) { return isUserUnlocked(user.getIdentifier()); } /** {@hide} */ @UnsupportedAppUsage + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true) public boolean isUserUnlocked(@UserIdInt int userId) { try { return mService.isUserUnlocked(userId); @@ -2087,15 +2185,15 @@ public class UserManager { * @hide */ @SystemApi - @RequiresPermission(anyOf = { - Manifest.permission.MANAGE_USERS, - Manifest.permission.INTERACT_ACROSS_USERS - }) + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true) public boolean isUserUnlockingOrUnlocked(@NonNull UserHandle user) { return isUserUnlockingOrUnlocked(user.getIdentifier()); } /** {@hide} */ + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true) public boolean isUserUnlockingOrUnlocked(@UserIdInt int userId) { try { return mService.isUserUnlockingOrUnlocked(userId); @@ -2136,12 +2234,13 @@ public class UserManager { /** * Returns the UserInfo object describing a specific user. - * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. * @param userId the user handle of the user whose information is being requested. * @return the UserInfo object for a specific user. * @hide */ @UnsupportedAppUsage + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}) public UserInfo getUserInfo(@UserIdInt int userId) { try { return mService.getUserInfo(userId); @@ -2231,6 +2330,7 @@ public class UserManager { * @param userHandle the UserHandle of the user for whom to retrieve the restrictions. */ @UnsupportedAppUsage + @RequiresPermission(Manifest.permission.MANAGE_USERS) public boolean hasBaseUserRestriction(@UserRestrictionKey String restrictionKey, UserHandle userHandle) { try { @@ -2271,6 +2371,7 @@ public class UserManager { * android.content.ComponentName, String)} instead. */ @Deprecated + @RequiresPermission(Manifest.permission.MANAGE_USERS) public void setUserRestriction(String key, boolean value) { setUserRestriction(key, value, Process.myUserHandle()); } @@ -2278,7 +2379,6 @@ public class UserManager { /** * @hide * Sets the value of a specific restriction on a specific user. - * Requires the MANAGE_USERS permission. * @param key the key of the restriction * @param value the value for the restriction * @param userHandle the user whose restriction is to be changed. @@ -2288,6 +2388,7 @@ public class UserManager { * android.content.ComponentName, String)} instead. */ @Deprecated + @RequiresPermission(Manifest.permission.MANAGE_USERS) public void setUserRestriction(String key, boolean value, UserHandle userHandle) { try { mService.setUserRestriction(key, value, userHandle.getIdentifier()); @@ -2440,21 +2541,32 @@ public class UserManager { * Creates a user with the specified name and options. For non-admin users, default user * restrictions will be applied. * - *

Requires {@link android.Manifest.permission#MANAGE_USERS} permission. + *

Requires {@link android.Manifest.permission#MANAGE_USERS}. + * {@link android.Manifest.permission#CREATE_USERS} suffices if flags are in + * com.android.server.pm.UserManagerService#ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION}. * - * @param name the user's name + * @param name the user's name * @param userType the type of user, such as {@link UserManager#USER_TYPE_FULL_GUEST}. - * @param flags UserInfo flags that specify user properties. - * @see UserInfo + * @param flags UserInfo flags that specify user properties. + * @return the {@link UserInfo} object for the created user, + * or throws {@link UserOperationException} if the user could not be created + * and calling app is targeting {@link android.os.Build.VERSION_CODES#R} or above + * (otherwise returns {@code null}). * - * @return the UserInfo object for the created user, or {@code null} if the user could not be - * created. + * @throws UserOperationException if the user could not be created and the calling app is + * targeting {@link android.os.Build.VERSION_CODES#R} or above. * @hide + * @see UserInfo */ + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}) public @Nullable UserInfo createUser(@Nullable String name, @NonNull String userType, @UserInfoFlag int flags) { try { - return mService.createUser(name, userType, flags); + return mService.createUserWithThrow(name, userType, flags); + } catch (ServiceSpecificException e) { + return returnNullOrThrowUserOperationException(e, + mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } @@ -2476,21 +2588,30 @@ public class UserManager { * *

All pre-created users are removed during system upgrade. * - *

Requires {@link android.Manifest.permission#MANAGE_USERS} permission. + *

Requires {@link android.Manifest.permission#MANAGE_USERS}. + * {@link android.Manifest.permission#CREATE_USERS} suffices if flags are in + * com.android.server.pm.UserManagerService#ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION}. * * @param userType the type of user, such as {@link UserManager#USER_TYPE_FULL_GUEST}. - * @return the UserInfo object for the created user, or {@code null} if the user could not be - * created. + * @return the {@link UserInfo} object for the created user, + * or throws {@link UserOperationException} if the user could not be created + * and calling app is targeting {@link android.os.Build.VERSION_CODES#R} or above + * (otherwise returns {@code null}). * - * @throw {@link IllegalArgumentException} if {@code flags} contains - * {@link UserInfo#FLAG_MANAGED_PROFILE}. + * @throws UserOperationException if the user could not be created and the calling app is + * targeting {@link android.os.Build.VERSION_CODES#R} or above. * * @hide */ - @RequiresPermission(android.Manifest.permission.MANAGE_USERS) - public @Nullable UserInfo preCreateUser(@NonNull String userType) { + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}) + public @Nullable UserInfo preCreateUser(@NonNull String userType) + throws UserOperationException { try { - return mService.preCreateUser(userType); + return mService.preCreateUserWithThrow(userType); + } catch (ServiceSpecificException e) { + return returnNullOrThrowUserOperationException(e, + mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } @@ -2500,16 +2621,28 @@ public class UserManager { * Creates a guest user and configures it. * @param context an application context * @param name the name to set for the user + * @return the {@link UserInfo} object for the created user, + * or throws {@link UserOperationException} if the user could not be created + * and calling app is targeting {@link android.os.Build.VERSION_CODES#R} or above + * (otherwise returns {@code null}). + * + * @throws UserOperationException if the user could not be created and the calling app is + * targeting {@link android.os.Build.VERSION_CODES#R} or above. * @hide */ - public UserInfo createGuest(Context context, String name) { + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}) + public UserInfo createGuest(Context context, String name) throws UserOperationException { UserInfo guest = null; try { - guest = mService.createUser(name, USER_TYPE_FULL_GUEST, 0); + guest = mService.createUserWithThrow(name, USER_TYPE_FULL_GUEST, 0); if (guest != null) { Settings.Secure.putStringForUser(context.getContentResolver(), Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id); } + } catch (ServiceSpecificException e) { + return returnNullOrThrowUserOperationException(e, + context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } @@ -2530,10 +2663,43 @@ public class UserManager { } } + /** + * Creates a user with the specified name and options as a profile of the context's user. + * + * @param name the user's name. + * @param userType the type of user, such as {@link UserManager#USER_TYPE_PROFILE_MANAGED}. + * @param disallowedPackages packages to not install for this profile. + * + * @return the {@link android.os.UserHandle} object for the created user, + * or throws {@link UserOperationException} if the user could not be created + * and calling app is targeting {@link android.os.Build.VERSION_CODES#R} or above + * (otherwise returns {@code null}). + * + * @throws UserOperationException if the user could not be created and the calling app is + * targeting {@link android.os.Build.VERSION_CODES#R} or above. + * + * @hide + */ + @SystemApi + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}) + @UserHandleAware + public @Nullable UserHandle createProfile(@NonNull String name, @NonNull String userType, + @Nullable String[] disallowedPackages) throws UserOperationException { + try { + return mService.createProfileForUserWithThrow(name, userType, 0, + mUserId, disallowedPackages).getUserHandle(); + } catch (ServiceSpecificException e) { + return returnNullOrThrowUserOperationException(e, + mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + /** * Creates a user with the specified name and options as a profile of another user. - * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. - * The type of profile must be specified using the given flags. + *

Requires MANAGE_USERS. CREATE_USERS suffices for ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION * * @param name the user's name * @param flags flags that identify the type of user and other properties. @@ -2546,6 +2712,8 @@ public class UserManager { * @hide */ @UnsupportedAppUsage + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}) @Deprecated public UserInfo createProfileForUser(String name, @UserInfoFlag int flags, @UserIdInt int userId) { @@ -2555,7 +2723,6 @@ public class UserManager { /** * Creates a user with the specified name and options as a profile of another user. - * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. * * @param name the user's name * @param userType the type of user, such as {@link UserManager#USER_TYPE_PROFILE_MANAGED}. @@ -2566,6 +2733,8 @@ public class UserManager { * could not be created. * @hide */ + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}) public UserInfo createProfileForUser(String name, @NonNull String userType, @UserInfoFlag int flags, @UserIdInt int userId) { return createProfileForUser(name, userType, flags, userId, null); @@ -2582,14 +2751,26 @@ public class UserManager { * @param userId new user will be a profile of this user. * @param disallowedPackages packages that will not be installed in the profile being created. * - * @return the {@link UserInfo} object for the created user, or null if the user - * could not be created. + * @return the {@link UserInfo} object for the created user, + * or throws {@link UserOperationException} if the user could not be created + * and calling app is targeting {@link android.os.Build.VERSION_CODES#R} or above + * (otherwise returns {@code null}). + * + * @throws UserOperationException if the user could not be created and the calling app is + * targeting {@link android.os.Build.VERSION_CODES#R} or above. * @hide */ + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}) public UserInfo createProfileForUser(String name, @NonNull String userType, - @UserInfoFlag int flags, @UserIdInt int userId, String[] disallowedPackages) { + @UserInfoFlag int flags, @UserIdInt int userId, String[] disallowedPackages) + throws UserOperationException { try { - return mService.createProfileForUser(name, userType, flags, userId, disallowedPackages); + return mService.createProfileForUserWithThrow(name, userType, flags, userId, + disallowedPackages); + } catch (ServiceSpecificException e) { + return returnNullOrThrowUserOperationException(e, + mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } @@ -2598,17 +2779,21 @@ public class UserManager { /** * Similar to {@link #createProfileForUser(String, String, int, int, String[])} * except bypassing the checking of {@link UserManager#DISALLOW_ADD_MANAGED_PROFILE}. - * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. * * @see #createProfileForUser(String, String, int, int, String[]) * @hide */ + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}) public UserInfo createProfileForUserEvenWhenDisallowed(String name, @NonNull String userType, @UserInfoFlag int flags, @UserIdInt int userId, - String[] disallowedPackages) { + String[] disallowedPackages) throws UserOperationException { try { - return mService.createProfileForUserEvenWhenDisallowed(name, userType, flags, + return mService.createProfileForUserEvenWhenDisallowedWithThrow(name, userType, flags, userId, disallowedPackages); + } catch (ServiceSpecificException e) { + return returnNullOrThrowUserOperationException(e, + mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } @@ -2619,19 +2804,30 @@ public class UserManager { * restrictions and adds shared accounts. * * @param name profile's name - * @return UserInfo object for the created user, or null if the user could not be created. + * @return the {@link UserInfo} object for the created user, + * or throws {@link UserOperationException} if the user could not be created + * and calling app is targeting {@link android.os.Build.VERSION_CODES#R} or above + * (otherwise returns {@code null}). + * + * @throws UserOperationException if the user could not be created and the calling app is + * targeting {@link android.os.Build.VERSION_CODES#R} or above. * @hide */ - public UserInfo createRestrictedProfile(String name) { + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}) + public UserInfo createRestrictedProfile(String name) throws UserOperationException { try { UserHandle parentUserHandle = Process.myUserHandle(); - UserInfo user = mService.createRestrictedProfile(name, + UserInfo user = mService.createRestrictedProfileWithThrow(name, parentUserHandle.getIdentifier()); if (user != null) { AccountManager.get(mContext).addSharedAccountsFromParentUser(parentUserHandle, UserHandle.of(user.id)); } return user; + } catch (ServiceSpecificException e) { + return returnNullOrThrowUserOperationException(e, + mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } @@ -2748,6 +2944,7 @@ public class UserManager { * @param accountOptions * @see #createUserCreationIntent(String, String, String, PersistableBundle) */ + @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setSeedAccountData(int userId, String accountName, String accountType, PersistableBundle accountOptions) { try { @@ -2779,6 +2976,7 @@ public class UserManager { * @param userId * @return */ + @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean markGuestForDeletion(@UserIdInt int userId) { try { return mService.markGuestForDeletion(userId); @@ -2790,8 +2988,6 @@ public class UserManager { /** * Sets the user as enabled, if such an user exists. * - *

Requires {@link android.Manifest.permission#MANAGE_USERS} permission. - * *

Note that the default is true, it's only that managed profiles might not be enabled. * Also ephemeral users can be disabled to indicate that their removal is in progress and they * shouldn't be re-entered. Therefore ephemeral users should not be re-enabled once disabled. @@ -2799,6 +2995,7 @@ public class UserManager { * @param userId the id of the profile to enable * @hide */ + @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserEnabled(@UserIdInt int userId) { try { mService.setUserEnabled(userId); @@ -2832,6 +3029,7 @@ public class UserManager { * * @hide */ + @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void evictCredentialEncryptionKey(@UserIdInt int userId) { try { mService.evictCredentialEncryptionKey(userId); @@ -2845,6 +3043,7 @@ public class UserManager { *

This API is not for use by third-party apps. It requires the {@code MANAGE_USERS} * permission.

*/ + @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public int getUserCount() { List users = getUsers(); return users != null ? users.size() : 1; @@ -2963,11 +3162,11 @@ public class UserManager { /** * Returns information for Primary user. - * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. * * @return the Primary user, null if not found. * @hide */ + @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public @Nullable UserInfo getPrimaryUser() { try { return mService.getPrimaryUser(); @@ -2983,6 +3182,7 @@ public class UserManager { * @return true if more users can be added, false if limit has been reached. * @hide */ + @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean canAddMoreUsers() { // TODO(b/142482943): UMS has different logic, excluding Demo and Profile from counting. Why // not here? The logic is inconsistent. See UMS.canAddMoreManagedProfiles @@ -3007,6 +3207,7 @@ public class UserManager { * @return true if more managed profiles can be added, false if limit has been reached. * @hide */ + @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean canAddMoreManagedProfiles(@UserIdInt int userId, boolean allowedToRemoveOne) { try { return mService.canAddMoreManagedProfiles(userId, allowedToRemoveOne); @@ -3036,12 +3237,15 @@ public class UserManager { * Note that this returns both enabled and not enabled profiles. See * {@link #getEnabledProfiles(int)} if you need only the enabled ones. * - * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. + *

Requires {@link android.Manifest.permission#MANAGE_USERS}. + * {@link android.Manifest.permission#CREATE_USERS} suffices if userId is the calling user. * @param userId profiles of this user will be returned. * @return the list of profiles. * @hide */ @UnsupportedAppUsage + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}, conditional = true) public List getProfiles(@UserIdInt int userId) { try { return mService.getProfiles(userId, false /* enabledOnly */); @@ -3057,7 +3261,6 @@ public class UserManager { * @param otherUser one of the two user handles to check. * @return true if the two users are in the same profile group. * - * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. * @hide */ @SystemApi @@ -3067,12 +3270,13 @@ public class UserManager { } /** - * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. + * Checks if the 2 provided user ids belong to the same profile group. * @param userId one of the two user ids to check. * @param otherUserId one of the two user ids to check. * @return true if the two user ids are in the same profile group. * @hide */ + @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isSameProfileGroup(@UserIdInt int userId, int otherUserId) { try { return mService.isSameProfileGroup(userId, otherUserId); @@ -3085,12 +3289,15 @@ public class UserManager { * Returns list of the profiles of userId including userId itself. * Note that this returns only enabled. * - * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. + *

Requires {@link android.Manifest.permission#MANAGE_USERS}. + * {@link android.Manifest.permission#CREATE_USERS} suffices if userId is the calling user. * @param userId profiles of this user will be returned. * @return the list of profiles. * @hide */ @UnsupportedAppUsage + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}, conditional = true) public List getEnabledProfiles(@UserIdInt int userId) { try { return mService.getProfiles(userId, true /* enabledOnly */); @@ -3114,6 +3321,28 @@ public class UserManager { return result; } + /** + * Returns a list of ids for profiles associated with the context user including the user + * itself. + * + * @param enabledOnly whether to return only {@link UserInfo#isEnabled() enabled} profiles + * @return A non-empty list of UserHandles associated with the calling user. + * + * @hide + */ + @SystemApi + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}, conditional = true) + @UserHandleAware + public @NonNull List getUserProfiles(boolean enabledOnly) { + final int[] userIds = getProfileIds(mUserId, enabledOnly); + final List result = new ArrayList<>(userIds.length); + for (int userId : userIds) { + result.add(UserHandle.of(userId)); + } + return result; + } + /** * Returns a list of ids for profiles associated with the specified user including the user * itself. @@ -3139,6 +3368,8 @@ public class UserManager { * @hide */ @UnsupportedAppUsage + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}, conditional = true) public int[] getProfileIdsWithDisabled(@UserIdInt int userId) { return getProfileIds(userId, false /* enabledOnly */); } @@ -3147,6 +3378,8 @@ public class UserManager { * @see #getProfileIds(int, boolean) * @hide */ + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}, conditional = true) public int[] getEnabledProfileIds(@UserIdInt int userId) { return getProfileIds(userId, true /* enabledOnly */); } @@ -3158,6 +3391,7 @@ public class UserManager { * * @hide */ + @RequiresPermission(Manifest.permission.MANAGE_USERS) public int getCredentialOwnerProfile(@UserIdInt int userId) { try { return mService.getCredentialOwnerProfile(userId); @@ -3173,6 +3407,7 @@ public class UserManager { * @hide */ @UnsupportedAppUsage + @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public UserInfo getProfileParent(@UserIdInt int userId) { try { return mService.getProfileParent(userId); @@ -3227,6 +3462,8 @@ public class UserManager { * * @see #isQuietModeEnabled(UserHandle) */ + @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, + Manifest.permission.MODIFY_QUIET_MODE}, conditional = true) public boolean requestQuietModeEnabled(boolean enableQuietMode, @NonNull UserHandle userHandle) { return requestQuietModeEnabled(enableQuietMode, userHandle, null); } @@ -3258,6 +3495,7 @@ public class UserManager { * @see {@link #requestQuietModeEnabled(boolean, UserHandle)} * @hide */ + @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean requestQuietModeEnabled( boolean enableQuietMode, @NonNull UserHandle userHandle, IntentSender target) { return requestQuietModeEnabled(enableQuietMode, userHandle, target, 0); @@ -3319,15 +3557,16 @@ public class UserManager { } /** - * Returns whether the calling app's user has a badge (generally to put on profiles' icons). + * Returns whether the user associated with the context has a badge (generally to put on + * profiles' icons). * * @return true if the user's icons should display a badge; false otherwise. - * * @see #getBadgedIconForUser more information about badging in general * @hide */ + @UserHandleAware public boolean hasBadge() { - return hasBadge(UserHandle.myUserId()); + return hasBadge(mUserId); } /** @@ -3485,11 +3724,12 @@ public class UserManager { /** * Removes a user and all associated data. - * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. * @param userId the integer handle of the user. * @hide */ @UnsupportedAppUsage + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}) public boolean removeUser(@UserIdInt int userId) { try { return mService.removeUser(userId); @@ -3507,7 +3747,8 @@ public class UserManager { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.MANAGE_USERS) + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}) public boolean removeUser(@NonNull UserHandle user) { if (user == null) { throw new IllegalArgumentException("user cannot be null"); @@ -3524,6 +3765,8 @@ public class UserManager { * @see {@link #removeUser(int)} * @hide */ + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}) public boolean removeUserEvenWhenDisallowed(@UserIdInt int userId) { try { return mService.removeUserEvenWhenDisallowed(userId); @@ -3534,12 +3777,12 @@ public class UserManager { /** * Updates the user's name. - * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. * * @param userId the user's integer id * @param name the new name for the user * @hide */ + @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserName(@UserIdInt int userId, String name) { try { mService.setUserName(userId, name); @@ -3549,16 +3792,16 @@ public class UserManager { } /** - * Updates the calling user's name. - * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. + * Updates the context user's name. * * @param name the new name for the user * @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.MANAGE_USERS) + @UserHandleAware public void setUserName(@Nullable String name) { - setUserName(getUserHandle(), name); + setUserName(mUserId, name); } /** @@ -3567,35 +3810,41 @@ public class UserManager { * @param icon the bitmap to set as the photo. * @hide */ - public void setUserIcon(@UserIdInt int userId, Bitmap icon) { + @RequiresPermission(android.Manifest.permission.MANAGE_USERS) + public void setUserIcon(@UserIdInt int userId, @NonNull Bitmap icon) + throws UserOperationException { try { mService.setUserIcon(userId, icon); + } catch (ServiceSpecificException e) { + throw UserOperationException.from(e); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } } /** - * Sets the calling user's photo. - * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. + * Sets the context user's photo. * * @param icon the bitmap to set as the photo. * @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.MANAGE_USERS) - public void setUserIcon(@NonNull Bitmap icon) { - setUserIcon(getUserHandle(), icon); + @UserHandleAware + public void setUserIcon(@NonNull Bitmap icon) throws UserOperationException { + setUserIcon(mUserId, icon); } /** - * Returns a file descriptor for the user's photo. PNG data can be read from this file. + * Returns a bitmap of the user's photo * @param userId the user whose photo we want to read. * @return a {@link Bitmap} of the user's photo, or null if there's no photo. * @see com.android.internal.util.UserIcons#getDefaultUserIcon for a default. * @hide */ @UnsupportedAppUsage + @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, + android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) public Bitmap getUserIcon(@UserIdInt int userId) { try { ParcelFileDescriptor fd = mService.getUserIcon(userId); @@ -3616,9 +3865,7 @@ public class UserManager { } /** - * Returns a Bitmap for the calling user's photo. - * Requires {@link android.Manifest.permission#MANAGE_USERS} - * or {@link android.Manifest.permission#GET_ACCOUNTS_PRIVILEGED} permissions. + * Returns a Bitmap for the context user's photo. * * @return a {@link Bitmap} of the user's photo, or null if there's no photo. * @see com.android.internal.util.UserIcons#getDefaultUserIcon for a default. @@ -3627,8 +3874,9 @@ public class UserManager { @SystemApi @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) + @UserHandleAware public @Nullable Bitmap getUserIcon() { - return getUserIcon(getUserHandle()); + return getUserIcon(mUserId); } /** @@ -3805,6 +4053,7 @@ public class UserManager { * @hide * Set restrictions that should apply to any future guest user that's created. */ + @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setDefaultGuestRestrictions(Bundle restrictions) { try { mService.setDefaultGuestRestrictions(restrictions); @@ -3817,6 +4066,7 @@ public class UserManager { * @hide * Gets the default guest restrictions. */ + @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public Bundle getDefaultGuestRestrictions() { try { return mService.getDefaultGuestRestrictions(); @@ -3847,6 +4097,7 @@ public class UserManager { * @param accountType The account type of the account to check for * @return whether the seed account was found */ + @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean someUserHasSeedAccount(String accountName, String accountType) { try { return mService.someUserHasSeedAccount(accountName, accountType); diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 490c47796472c..11f990956b078 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2369,7 +2369,7 @@ -