summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Saumya Pathak <saumyap@google.com> 2023-06-30 13:46:44 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2023-06-30 13:46:44 +0000
commitaa10ad938e7989f43b120169fa4092253602fd2a (patch)
tree33644a6f2059da9d7b2447ad86b6ea2aec5ea0e4
parent382508e8a2c71535254379ca697840dbdfbdf62e (diff)
parent95e76bc49851366edfa88da9448caf983adc287a (diff)
Merge "Added Private profile user type"
-rw-r--r--core/api/test-current.txt1
-rw-r--r--core/java/android/content/pm/UserInfo.java4
-rw-r--r--core/java/android/os/UserManager.java35
-rw-r--r--services/core/java/com/android/server/pm/UserTypeDetails.java8
-rw-r--r--services/core/java/com/android/server/pm/UserTypeFactory.java35
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java46
6 files changed, 129 insertions, 0 deletions
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index bac3f4a75973..7c3d8fb856a4 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1061,6 +1061,7 @@ package android.content.pm {
method public boolean isMain();
method public boolean isManagedProfile();
method @Deprecated public boolean isPrimary();
+ method public boolean isPrivateProfile();
method public boolean isProfile();
method public boolean isQuietModeEnabled();
method public boolean isRestricted();
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 7f42c1a08f9c..9f4459d6591b 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -390,6 +390,10 @@ public class UserInfo implements Parcelable {
return UserManager.isUserTypeCommunalProfile(userType);
}
+ public boolean isPrivateProfile() {
+ return UserManager.isUserTypePrivateProfile(userType);
+ }
+
@UnsupportedAppUsage
public boolean isEnabled() {
return (flags & FLAG_DISABLED) != FLAG_DISABLED;
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 84dc79b92c55..ba1f979b4514 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -159,6 +159,13 @@ public class UserManager {
@SystemApi
public static final String USER_TYPE_PROFILE_CLONE = "android.os.usertype.profile.CLONE";
+
+ /**
+ * User type representing a private profile.
+ * @hide
+ */
+ public static final String USER_TYPE_PROFILE_PRIVATE = "android.os.usertype.profile.PRIVATE";
+
/**
* User type representing a generic profile for testing purposes. Only on debuggable builds.
* @hide
@@ -2858,6 +2865,16 @@ public class UserManager {
}
/**
+ * Returns whether the user type is a
+ * {@link UserManager#USER_TYPE_PROFILE_PRIVATE private profile}.
+ *
+ * @hide
+ */
+ public static boolean isUserTypePrivateProfile(@Nullable String userType) {
+ return USER_TYPE_PROFILE_PRIVATE.equals(userType);
+ }
+
+ /**
* @hide
* @deprecated Use {@link #isRestrictedProfile()}
*/
@@ -3146,6 +3163,24 @@ public class UserManager {
}
/**
+ * Checks if the context user is a private profile.
+ *
+ * @return whether the context user is a private profile.
+ *
+ * @see android.os.UserManager#USER_TYPE_PROFILE_PRIVATE
+ * @hide
+ */
+ @UserHandleAware(
+ requiresAnyOfPermissionsIfNotCallerProfileGroup = {
+ android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.QUERY_USERS,
+ android.Manifest.permission.INTERACT_ACROSS_USERS})
+ @SuppressAutoDoc
+ public boolean isPrivateProfile() {
+ return isUserTypePrivateProfile(getProfileType());
+ }
+
+ /**
* Checks if the context user is an ephemeral user.
*
* @return whether the context user is an ephemeral user.
diff --git a/services/core/java/com/android/server/pm/UserTypeDetails.java b/services/core/java/com/android/server/pm/UserTypeDetails.java
index 9ebb8d6ac4be..7bdcd685a2e9 100644
--- a/services/core/java/com/android/server/pm/UserTypeDetails.java
+++ b/services/core/java/com/android/server/pm/UserTypeDetails.java
@@ -633,4 +633,12 @@ public final class UserTypeDetails {
public boolean isCommunalProfile() {
return UserManager.isUserTypeCommunalProfile(mName);
}
+
+ /**
+ * Returns whether the user type is a private profile
+ * (i.e. {@link UserManager#USER_TYPE_PROFILE_PRIVATE}).
+ */
+ public boolean isPrivateProfile() {
+ return UserManager.isUserTypePrivateProfile(mName);
+ }
}
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index 1569e06bd06d..f7967c0a60d9 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -35,6 +35,7 @@ import static android.os.UserManager.USER_TYPE_FULL_SYSTEM;
import static android.os.UserManager.USER_TYPE_PROFILE_CLONE;
import static android.os.UserManager.USER_TYPE_PROFILE_COMMUNAL;
import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED;
+import static android.os.UserManager.USER_TYPE_PROFILE_PRIVATE;
import static android.os.UserManager.USER_TYPE_PROFILE_TEST;
import static android.os.UserManager.USER_TYPE_SYSTEM_HEADLESS;
@@ -108,6 +109,7 @@ public final class UserTypeFactory {
builders.put(USER_TYPE_SYSTEM_HEADLESS, getDefaultTypeSystemHeadless());
builders.put(USER_TYPE_PROFILE_CLONE, getDefaultTypeProfileClone());
builders.put(USER_TYPE_PROFILE_COMMUNAL, getDefaultTypeProfileCommunal());
+ builders.put(USER_TYPE_PROFILE_PRIVATE, getDefaultTypeProfilePrivate());
if (Build.IS_DEBUGGABLE) {
builders.put(USER_TYPE_PROFILE_TEST, getDefaultTypeProfileTest());
}
@@ -264,6 +266,39 @@ public final class UserTypeFactory {
}
/**
+ * Returns the Builder for the default {@link UserManager#USER_TYPE_PROFILE_PRIVATE}
+ * configuration.
+ */
+ private static UserTypeDetails.Builder getDefaultTypeProfilePrivate() {
+ return new UserTypeDetails.Builder()
+ .setName(USER_TYPE_PROFILE_PRIVATE)
+ .setBaseType(FLAG_PROFILE)
+ .setMaxAllowedPerParent(1)
+ .setLabel(0)
+ .setIconBadge(com.android.internal.R.drawable.ic_test_icon_badge_experiment)
+ .setBadgePlain(com.android.internal.R.drawable.ic_test_badge_experiment)
+ .setBadgeNoBackground(com.android.internal.R.drawable.ic_test_badge_no_background)
+ .setStatusBarIcon(com.android.internal.R.drawable.ic_test_badge_experiment)
+ .setBadgeLabels(
+ com.android.internal.R.string.managed_profile_label_badge,
+ com.android.internal.R.string.managed_profile_label_badge_2,
+ com.android.internal.R.string.managed_profile_label_badge_3)
+ .setBadgeColors(
+ com.android.internal.R.color.profile_badge_2)
+ .setDarkThemeBadgeColors(
+ com.android.internal.R.color.profile_badge_2_dark)
+ .setDefaultRestrictions(getDefaultProfileRestrictions())
+ .setDefaultSecureSettings(getDefaultNonManagedProfileSecureSettings())
+ .setDefaultUserProperties(new UserProperties.Builder()
+ .setStartWithParent(true)
+ .setCredentialShareableWithParent(false)
+ .setMediaSharedWithParent(false)
+ .setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_SEPARATE)
+ .setCrossProfileIntentFilterAccessControl(
+ UserProperties.CROSS_PROFILE_INTENT_FILTER_ACCESS_LEVEL_SYSTEM));
+ }
+
+ /**
* Returns the Builder for the default {@link UserManager#USER_TYPE_FULL_SECONDARY}
* configuration.
*/
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 7d0f36133a9c..dd681aa85c3f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -265,6 +265,52 @@ public final class UserManagerTest {
assertWithMessage("Communal profile not visible").that(umCommunal.isUserVisible()).isTrue();
}
+ @Test
+ public void testPrivateProfile() throws Exception {
+ UserHandle mainUser = mUserManager.getMainUser();
+ assumeTrue("Main user is null", mainUser != null);
+ // Get the default properties for private profile user type.
+ final UserTypeDetails userTypeDetails =
+ UserTypeFactory.getUserTypes().get(UserManager.USER_TYPE_PROFILE_PRIVATE);
+ assertWithMessage("No %s type on device", UserManager.USER_TYPE_PROFILE_PRIVATE)
+ .that(userTypeDetails).isNotNull();
+ final UserProperties typeProps = userTypeDetails.getDefaultUserPropertiesReference();
+
+ // Test that only one private profile can be created
+ final int mainUserId = mainUser.getIdentifier();
+ UserInfo userInfo = createProfileForUser("Private profile1",
+ UserManager.USER_TYPE_PROFILE_PRIVATE,
+ mainUserId);
+ assertThat(userInfo).isNotNull();
+ UserInfo userInfo2 = createProfileForUser("Private profile2",
+ UserManager.USER_TYPE_PROFILE_PRIVATE,
+ mainUserId);
+ assertThat(userInfo2).isNull();
+
+ // Check that the new private profile has the expected properties (relative to the defaults)
+ // provided that the test caller has the necessary permissions.
+ UserProperties privateProfileUserProperties =
+ mUserManager.getUserProperties(UserHandle.of(userInfo.id));
+ assertThat(typeProps.getShowInLauncher())
+ .isEqualTo(privateProfileUserProperties.getShowInLauncher());
+ assertThrows(SecurityException.class, privateProfileUserProperties::getStartWithParent);
+ assertThrows(SecurityException.class,
+ privateProfileUserProperties::getCrossProfileIntentFilterAccessControl);
+ assertThat(typeProps.isMediaSharedWithParent())
+ .isEqualTo(privateProfileUserProperties.isMediaSharedWithParent());
+ assertThat(typeProps.isCredentialShareableWithParent())
+ .isEqualTo(privateProfileUserProperties.isCredentialShareableWithParent());
+ assertThrows(SecurityException.class, privateProfileUserProperties::getDeleteAppWithParent);
+
+ // Verify private profile parent
+ assertThat(mUserManager.getProfileParent(mainUserId)).isNull();
+ UserInfo parentProfileInfo = mUserManager.getProfileParent(userInfo.id);
+ assertThat(parentProfileInfo).isNotNull();
+ assertThat(mainUserId).isEqualTo(parentProfileInfo.id);
+ removeUser(userInfo.id);
+ assertThat(mUserManager.getProfileParent(mainUserId)).isNull();
+ }
+
@MediumTest
@Test
public void testAdd2Users() throws Exception {