diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 7bbabb6632695..a3b4a5b5b9dc3 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -8495,6 +8495,7 @@ package android.os { 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(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isCloneProfile(); 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(); @@ -8508,6 +8509,7 @@ package android.os { 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); + method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean sharesMediaWithParent(); 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"; field public static final String DISALLOW_RUN_IN_BACKGROUND = "no_run_in_background"; @@ -8521,6 +8523,7 @@ package android.os { 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_CLONE = "android.os.usertype.profile.CLONE"; 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"; } diff --git a/core/api/test-current.txt b/core/api/test-current.txt index ae1cbf77dd8a7..09e0088cf9169 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -817,6 +817,7 @@ package android.content.pm { method public int describeContents(); method public android.os.UserHandle getUserHandle(); method public boolean isAdmin(); + method public boolean isCloneProfile(); method public boolean isDemo(); method public boolean isEnabled(); method public boolean isEphemeral(); diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java index cfb6e1b572aaa..5a89708b58831 100644 --- a/core/java/android/content/pm/UserInfo.java +++ b/core/java/android/content/pm/UserInfo.java @@ -321,6 +321,10 @@ public class UserInfo implements Parcelable { return UserManager.isUserTypeManagedProfile(userType); } + public boolean isCloneProfile() { + return UserManager.isUserTypeCloneProfile(userType); + } + @UnsupportedAppUsage public boolean isEnabled() { return (flags & FLAG_DISABLED) != FLAG_DISABLED; diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index 087568defb270..34f2c103f8660 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -99,6 +99,8 @@ interface IUserManager { boolean someUserHasSeedAccount(in String accountName, in String accountType); boolean isProfile(int userId); boolean isManagedProfile(int userId); + boolean isCloneProfile(int userId); + boolean sharesMediaWithParent(int userId); boolean isDemoUser(int userId); boolean isPreCreated(int userId); UserInfo createProfileForUserEvenWhenDisallowedWithThrow(in String name, in String userType, int flags, diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 5069e03191197..d4de4fa655265 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -25,6 +25,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.StringDef; +import android.annotation.SuppressAutoDoc; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; @@ -135,6 +136,16 @@ public class UserManager { @SystemApi public static final String USER_TYPE_PROFILE_MANAGED = "android.os.usertype.profile.MANAGED"; + /** + * User type representing a clone profile. Clone profile is a user profile type used to run + * second instance of an otherwise single user App (eg, messengers). Only the primary user + * is allowed to have a clone profile. + * + * @hide + */ + @SystemApi + public static final String USER_TYPE_PROFILE_CLONE = "android.os.usertype.profile.CLONE"; + /** * User type representing a generic profile for testing purposes. Only on debuggable builds. * @hide @@ -1983,6 +1994,14 @@ public class UserManager { return USER_TYPE_FULL_DEMO.equals(userType); } + /** + * Returns whether the user type is a {@link UserManager#USER_TYPE_PROFILE_CLONE clone user}. + * @hide + */ + public static boolean isUserTypeCloneProfile(String userType) { + return USER_TYPE_PROFILE_CLONE.equals(userType); + } + /** * Returns the enum defined in the statsd UserLifecycleJourneyReported atom corresponding to the * user type. @@ -2232,6 +2251,31 @@ public class UserManager { } } + /** + * Checks if the context user is a clone 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 the user. + * + * @return whether the context user is a clone profile. + * + * @see android.os.UserManager#USER_TYPE_PROFILE_CLONE + * @hide + */ + @SystemApi + @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, + Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true) + @UserHandleAware + @SuppressAutoDoc + public boolean isCloneProfile() { + try { + return mService.isCloneProfile(mUserId); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + /** * Checks if the calling app is running as an ephemeral user. * @@ -4063,6 +4107,31 @@ public class UserManager { } } + /** + * If the user is a {@link UserManager#isProfile profile}, checks if the user + * shares media with its parent user (the user that created this profile). + * Returns false for any other type of user. + * + *
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 as the user. + * + * @return true if the user shares media with its parent user, false otherwise. + * @hide + */ + @SystemApi + @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, + Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true) + @UserHandleAware + @SuppressAutoDoc + public boolean sharesMediaWithParent() { + try { + return mService.sharesMediaWithParent(mUserId); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + /** * Removes a user and all associated data. * @param userId the integer handle of the user. diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index fe19956ce8ce0..2a0257dd2a209 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -1506,6 +1506,26 @@ public class UserManagerService extends IUserManager.Stub { } } + @Override + public boolean isCloneProfile(@UserIdInt int userId) { + checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId, "isCloneProfile"); + synchronized (mUsersLock) { + UserInfo userInfo = getUserInfoLU(userId); + return userInfo != null && userInfo.isCloneProfile(); + } + } + + @Override + public boolean sharesMediaWithParent(@UserIdInt int userId) { + checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId, + "sharesMediaWithParent"); + synchronized (mUsersLock) { + UserTypeDetails userTypeDetails = getUserTypeDetailsNoChecks(userId); + return userTypeDetails != null ? userTypeDetails.isProfile() + && userTypeDetails.sharesMediaWithParent() : false; + } + } + @Override public boolean isUserUnlockingOrUnlocked(@UserIdInt int userId) { checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId, diff --git a/services/core/java/com/android/server/pm/UserTypeDetails.java b/services/core/java/com/android/server/pm/UserTypeDetails.java index 17ce386e37705..6824f7d8fa558 100644 --- a/services/core/java/com/android/server/pm/UserTypeDetails.java +++ b/services/core/java/com/android/server/pm/UserTypeDetails.java @@ -149,6 +149,13 @@ public final class UserTypeDetails { */ private final @Nullable int[] mDarkThemeBadgeColors; + /** + * Denotes if the user shares media with its parent user. + * + *
Default value is false
+ */
+ private final boolean mSharesMediaWithParent;
+
private UserTypeDetails(@NonNull String name, boolean enabled, int maxAllowed,
@UserInfoFlag int baseType, @UserInfoFlag int defaultUserInfoPropertyFlags, int label,
int maxAllowedPerParent,
@@ -158,7 +165,8 @@ public final class UserTypeDetails {
@Nullable Bundle defaultRestrictions,
@Nullable Bundle defaultSystemSettings,
@Nullable Bundle defaultSecureSettings,
- @Nullable List