Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ab75d2ce authored by Adam Bookatz's avatar Adam Bookatz
Browse files

Introduce Communal Profile user type [minimalist]

Introduces a new user type - the Communal Profile - which is a profile
that has no parent and which is created and starts starts on boot (for
devices so configured). The profile can be accessed by any person, even
over the lockscreen and even if all human users are locked, and  is
always regarded as visible and running.

This cl does NOT include the communal profile as being part of the
profile group of other users. It is minimalist, in that it simply
creates and starts the profile; SysUi can make use of it, but external
parties (like the Launcher) would require further work to be able to do
so.

This cl is introductory. Some future tasks:
* switching users does not preserve the communal profile windows. The
  profile is still available, but each user sees its own windows.

Test: atest com.android.server.pm.UserVisibilityMediatorSUSDTest#testStartVisibleBgProfile_communalProfile
Test: atest com.android.server.pm.UserManagerTest
Test: atest UserManagerServiceUserPropertiesTest
Test: atest UserManagerServiceUserTypeTest
Test: atest UserControllerTest UserVisibilityMediatorMUPANDTest
Bug: 274838657
Bug: 276473320
Change-Id: Ib0e4e52c10f0e95913ddfde606d6995de3538f27
parent de7843f5
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -1049,6 +1049,7 @@ package android.content.pm {
    method public android.os.UserHandle getUserHandle();
    method public android.os.UserHandle getUserHandle();
    method public boolean isAdmin();
    method public boolean isAdmin();
    method public boolean isCloneProfile();
    method public boolean isCloneProfile();
    method public boolean isCommunalProfile();
    method public boolean isDemo();
    method public boolean isDemo();
    method public boolean isEnabled();
    method public boolean isEnabled();
    method public boolean isEphemeral();
    method public boolean isEphemeral();
+4 −0
Original line number Original line Diff line number Diff line
@@ -386,6 +386,10 @@ public class UserInfo implements Parcelable {
        return UserManager.isUserTypeCloneProfile(userType);
        return UserManager.isUserTypeCloneProfile(userType);
    }
    }


    public boolean isCommunalProfile() {
        return UserManager.isUserTypeCommunalProfile(userType);
    }

    @UnsupportedAppUsage
    @UnsupportedAppUsage
    public boolean isEnabled() {
    public boolean isEnabled() {
        return (flags & FLAG_DISABLED) != FLAG_DISABLED;
        return (flags & FLAG_DISABLED) != FLAG_DISABLED;
+45 −2
Original line number Original line Diff line number Diff line
@@ -62,6 +62,7 @@ public final class UserProperties implements Parcelable {
    private static final String ATTR_CREDENTIAL_SHAREABLE_WITH_PARENT =
    private static final String ATTR_CREDENTIAL_SHAREABLE_WITH_PARENT =
            "credentialShareableWithParent";
            "credentialShareableWithParent";
    private static final String ATTR_DELETE_APP_WITH_PARENT = "deleteAppWithParent";
    private static final String ATTR_DELETE_APP_WITH_PARENT = "deleteAppWithParent";
    private static final String ATTR_ALWAYS_VISIBLE = "alwaysVisible";


    /** Index values of each property (to indicate whether they are present in this object). */
    /** Index values of each property (to indicate whether they are present in this object). */
    @IntDef(prefix = "INDEX_", value = {
    @IntDef(prefix = "INDEX_", value = {
@@ -76,6 +77,7 @@ public final class UserProperties implements Parcelable {
            INDEX_MEDIA_SHARED_WITH_PARENT,
            INDEX_MEDIA_SHARED_WITH_PARENT,
            INDEX_CREDENTIAL_SHAREABLE_WITH_PARENT,
            INDEX_CREDENTIAL_SHAREABLE_WITH_PARENT,
            INDEX_DELETE_APP_WITH_PARENT,
            INDEX_DELETE_APP_WITH_PARENT,
            INDEX_ALWAYS_VISIBLE,
    })
    })
    @Retention(RetentionPolicy.SOURCE)
    @Retention(RetentionPolicy.SOURCE)
    private @interface PropertyIndex {
    private @interface PropertyIndex {
@@ -91,6 +93,7 @@ public final class UserProperties implements Parcelable {
    private static final int INDEX_MEDIA_SHARED_WITH_PARENT = 8;
    private static final int INDEX_MEDIA_SHARED_WITH_PARENT = 8;
    private static final int INDEX_CREDENTIAL_SHAREABLE_WITH_PARENT = 9;
    private static final int INDEX_CREDENTIAL_SHAREABLE_WITH_PARENT = 9;
    private static final int INDEX_DELETE_APP_WITH_PARENT = 10;
    private static final int INDEX_DELETE_APP_WITH_PARENT = 10;
    private static final int INDEX_ALWAYS_VISIBLE = 11;
    /** A bit set, mapping each PropertyIndex to whether it is present (1) or absent (0). */
    /** A bit set, mapping each PropertyIndex to whether it is present (1) or absent (0). */
    private long mPropertiesPresent = 0;
    private long mPropertiesPresent = 0;


@@ -316,6 +319,7 @@ public final class UserProperties implements Parcelable {
                    orig.getCrossProfileIntentFilterAccessControl());
                    orig.getCrossProfileIntentFilterAccessControl());
            setCrossProfileIntentResolutionStrategy(orig.getCrossProfileIntentResolutionStrategy());
            setCrossProfileIntentResolutionStrategy(orig.getCrossProfileIntentResolutionStrategy());
            setDeleteAppWithParent(orig.getDeleteAppWithParent());
            setDeleteAppWithParent(orig.getDeleteAppWithParent());
            setAlwaysVisible(orig.getAlwaysVisible());
        }
        }
        if (hasManagePermission) {
        if (hasManagePermission) {
            // Add items that require MANAGE_USERS or stronger.
            // Add items that require MANAGE_USERS or stronger.
@@ -439,6 +443,24 @@ public final class UserProperties implements Parcelable {
    }
    }
    private boolean mDeleteAppWithParent;
    private boolean mDeleteAppWithParent;


    /**
     * Returns whether the user should always
     * be {@link android.os.UserManager#isUserVisible() visible}.
     * The intended usage is for the Communal Profile, which is running and accessible at all times.
     * @hide
     */
    public boolean getAlwaysVisible() {
        if (isPresent(INDEX_ALWAYS_VISIBLE)) return mAlwaysVisible;
        if (mDefaultProperties != null) return mDefaultProperties.mAlwaysVisible;
        throw new SecurityException("You don't have permission to query alwaysVisible");
    }
    /** @hide */
    public void setAlwaysVisible(boolean val) {
        this.mAlwaysVisible = val;
        setPresent(INDEX_ALWAYS_VISIBLE);
    }
    private boolean mAlwaysVisible;

    /**
    /**
     * Return whether, and how, select user restrictions or device policies should be inherited
     * Return whether, and how, select user restrictions or device policies should be inherited
     * from other user.
     * from other user.
@@ -632,6 +654,7 @@ public final class UserProperties implements Parcelable {
                + ", mMediaSharedWithParent=" + isMediaSharedWithParent()
                + ", mMediaSharedWithParent=" + isMediaSharedWithParent()
                + ", mCredentialShareableWithParent=" + isCredentialShareableWithParent()
                + ", mCredentialShareableWithParent=" + isCredentialShareableWithParent()
                + ", mDeleteAppWithParent=" + getDeleteAppWithParent()
                + ", mDeleteAppWithParent=" + getDeleteAppWithParent()
                + ", mAlwaysVisible=" + getAlwaysVisible()
                + "}";
                + "}";
    }
    }


@@ -658,6 +681,7 @@ public final class UserProperties implements Parcelable {
        pw.println(prefix + "    mCredentialShareableWithParent="
        pw.println(prefix + "    mCredentialShareableWithParent="
                + isCredentialShareableWithParent());
                + isCredentialShareableWithParent());
        pw.println(prefix + "    mDeleteAppWithParent=" + getDeleteAppWithParent());
        pw.println(prefix + "    mDeleteAppWithParent=" + getDeleteAppWithParent());
        pw.println(prefix + "    mAlwaysVisible=" + getAlwaysVisible());
    }
    }


    /**
    /**
@@ -724,6 +748,9 @@ public final class UserProperties implements Parcelable {
                case ATTR_DELETE_APP_WITH_PARENT:
                case ATTR_DELETE_APP_WITH_PARENT:
                    setDeleteAppWithParent(parser.getAttributeBoolean(i));
                    setDeleteAppWithParent(parser.getAttributeBoolean(i));
                    break;
                    break;
                case ATTR_ALWAYS_VISIBLE:
                    setAlwaysVisible(parser.getAttributeBoolean(i));
                    break;
                default:
                default:
                    Slog.w(LOG_TAG, "Skipping unknown property " + attributeName);
                    Slog.w(LOG_TAG, "Skipping unknown property " + attributeName);
            }
            }
@@ -783,6 +810,10 @@ public final class UserProperties implements Parcelable {
            serializer.attributeBoolean(null, ATTR_DELETE_APP_WITH_PARENT,
            serializer.attributeBoolean(null, ATTR_DELETE_APP_WITH_PARENT,
                    mDeleteAppWithParent);
                    mDeleteAppWithParent);
        }
        }
        if (isPresent(INDEX_ALWAYS_VISIBLE)) {
            serializer.attributeBoolean(null, ATTR_ALWAYS_VISIBLE,
                    mAlwaysVisible);
        }
    }
    }


    // For use only with an object that has already had any permission-lacking fields stripped out.
    // For use only with an object that has already had any permission-lacking fields stripped out.
@@ -800,6 +831,7 @@ public final class UserProperties implements Parcelable {
        dest.writeBoolean(mMediaSharedWithParent);
        dest.writeBoolean(mMediaSharedWithParent);
        dest.writeBoolean(mCredentialShareableWithParent);
        dest.writeBoolean(mCredentialShareableWithParent);
        dest.writeBoolean(mDeleteAppWithParent);
        dest.writeBoolean(mDeleteAppWithParent);
        dest.writeBoolean(mAlwaysVisible);
    }
    }


    /**
    /**
@@ -821,6 +853,7 @@ public final class UserProperties implements Parcelable {
        mMediaSharedWithParent = source.readBoolean();
        mMediaSharedWithParent = source.readBoolean();
        mCredentialShareableWithParent = source.readBoolean();
        mCredentialShareableWithParent = source.readBoolean();
        mDeleteAppWithParent = source.readBoolean();
        mDeleteAppWithParent = source.readBoolean();
        mAlwaysVisible = source.readBoolean();
    }
    }


    @Override
    @Override
@@ -859,6 +892,7 @@ public final class UserProperties implements Parcelable {
        private boolean mMediaSharedWithParent = false;
        private boolean mMediaSharedWithParent = false;
        private boolean mCredentialShareableWithParent = false;
        private boolean mCredentialShareableWithParent = false;
        private boolean mDeleteAppWithParent = false;
        private boolean mDeleteAppWithParent = false;
        private boolean mAlwaysVisible = false;


        public Builder setShowInLauncher(@ShowInLauncher int showInLauncher) {
        public Builder setShowInLauncher(@ShowInLauncher int showInLauncher) {
            mShowInLauncher = showInLauncher;
            mShowInLauncher = showInLauncher;
@@ -926,6 +960,12 @@ public final class UserProperties implements Parcelable {
            return this;
            return this;
        }
        }


        /** Sets the value for {@link #mAlwaysVisible}*/
        public Builder setAlwaysVisible(boolean alwaysVisible) {
            mAlwaysVisible = alwaysVisible;
            return this;
        }

        /** Builds a UserProperties object with *all* values populated. */
        /** Builds a UserProperties object with *all* values populated. */
        public UserProperties build() {
        public UserProperties build() {
            return new UserProperties(
            return new UserProperties(
@@ -939,7 +979,8 @@ public final class UserProperties implements Parcelable {
                    mCrossProfileIntentResolutionStrategy,
                    mCrossProfileIntentResolutionStrategy,
                    mMediaSharedWithParent,
                    mMediaSharedWithParent,
                    mCredentialShareableWithParent,
                    mCredentialShareableWithParent,
                    mDeleteAppWithParent);
                    mDeleteAppWithParent,
                    mAlwaysVisible);
        }
        }
    } // end Builder
    } // end Builder


@@ -954,7 +995,8 @@ public final class UserProperties implements Parcelable {
            @CrossProfileIntentResolutionStrategy int crossProfileIntentResolutionStrategy,
            @CrossProfileIntentResolutionStrategy int crossProfileIntentResolutionStrategy,
            boolean mediaSharedWithParent,
            boolean mediaSharedWithParent,
            boolean credentialShareableWithParent,
            boolean credentialShareableWithParent,
            boolean deleteAppWithParent) {
            boolean deleteAppWithParent,
            boolean alwaysVisible) {
        mDefaultProperties = null;
        mDefaultProperties = null;
        setShowInLauncher(showInLauncher);
        setShowInLauncher(showInLauncher);
        setStartWithParent(startWithParent);
        setStartWithParent(startWithParent);
@@ -967,5 +1009,6 @@ public final class UserProperties implements Parcelable {
        setMediaSharedWithParent(mediaSharedWithParent);
        setMediaSharedWithParent(mediaSharedWithParent);
        setCredentialShareableWithParent(credentialShareableWithParent);
        setCredentialShareableWithParent(credentialShareableWithParent);
        setDeleteAppWithParent(deleteAppWithParent);
        setDeleteAppWithParent(deleteAppWithParent);
        setAlwaysVisible(alwaysVisible);
    }
    }
}
}
+1 −0
Original line number Original line Diff line number Diff line
@@ -60,6 +60,7 @@ interface IUserManager {
    ParcelFileDescriptor getUserIcon(int userId);
    ParcelFileDescriptor getUserIcon(int userId);
    UserInfo getPrimaryUser();
    UserInfo getPrimaryUser();
    int getMainUserId();
    int getMainUserId();
    int getCommunalProfileId();
    int getPreviousFullUserToEnterForeground();
    int getPreviousFullUserToEnterForeground();
    List<UserInfo> getUsers(boolean excludePartial, boolean excludeDying, boolean excludePreCreated);
    List<UserInfo> getUsers(boolean excludePartial, boolean excludeDying, boolean excludePreCreated);
    List<UserInfo> getProfiles(int userId, boolean enabledOnly);
    List<UserInfo> getProfiles(int userId, boolean enabledOnly);
+58 −0
Original line number Original line Diff line number Diff line
@@ -165,6 +165,12 @@ public class UserManager {
     */
     */
    public static final String USER_TYPE_PROFILE_TEST = "android.os.usertype.profile.TEST";
    public static final String USER_TYPE_PROFILE_TEST = "android.os.usertype.profile.TEST";


    /**
     * User type representing a communal profile, which is shared by all users of the device.
     * @hide
     */
    public static final String USER_TYPE_PROFILE_COMMUNAL = "android.os.usertype.profile.COMMUNAL";

    /**
    /**
     * User type representing a {@link UserHandle#USER_SYSTEM system} user that is <b>not</b> a
     * User type representing a {@link UserHandle#USER_SYSTEM system} user that is <b>not</b> a
     * human user.
     * human user.
@@ -2131,6 +2137,16 @@ public class UserManager {
                .getBoolean(com.android.internal.R.bool.config_guestUserAllowEphemeralStateChange);
                .getBoolean(com.android.internal.R.bool.config_guestUserAllowEphemeralStateChange);
    }
    }


    /**
     * Returns whether the device is configured to support a Communal Profile.
     * @hide
     */
    public static boolean isCommunalProfileEnabled() {
        return SystemProperties.getBoolean("persist.fw.omnipresent_communal_user",
                Resources.getSystem()
                        .getBoolean(com.android.internal.R.bool.config_omnipresentCommunalUser));
    }

    /**
    /**
     * Returns whether multiple admins are enabled on the device
     * Returns whether multiple admins are enabled on the device
     * @hide
     * @hide
@@ -2438,6 +2454,38 @@ public class UserManager {
            throw re.rethrowFromSystemServer();
            throw re.rethrowFromSystemServer();
        }
        }
    }
    }
    /**
     * Returns the designated "communal profile" of the device, or {@code null} if there is none.
     * @hide
     */
    @RequiresPermission(anyOf = {
            Manifest.permission.MANAGE_USERS,
            Manifest.permission.CREATE_USERS,
            Manifest.permission.QUERY_USERS})
    public @Nullable UserHandle getCommunalProfile() {
        try {
            final int userId = mService.getCommunalProfileId();
            if (userId == UserHandle.USER_NULL) {
                return null;
            }
            return UserHandle.of(userId);
        } catch (RemoteException re) {
            throw re.rethrowFromSystemServer();
        }
    }

    /**
     * Returns {@code true} if the given user is the designated "communal profile" of the device.
     * @hide
     */
    @RequiresPermission(anyOf = {
            Manifest.permission.MANAGE_USERS,
            Manifest.permission.CREATE_USERS,
            Manifest.permission.QUERY_USERS})
    public boolean isCommunalProfile(@UserIdInt int userId) {
        final UserInfo user = getUserInfo(userId);
        return user != null && user.isCommunalProfile();
    }


    /**
    /**
     * Used to check if the context user is an admin user. An admin user may be allowed to
     * Used to check if the context user is an admin user. An admin user may be allowed to
@@ -2539,6 +2587,15 @@ public class UserManager {
        return USER_TYPE_PROFILE_CLONE.equals(userType);
        return USER_TYPE_PROFILE_CLONE.equals(userType);
    }
    }


    /**
     * Returns whether the user type is a
     * {@link UserManager#USER_TYPE_PROFILE_COMMUNAL communal profile}.
     * @hide
     */
    public static boolean isUserTypeCommunalProfile(@Nullable String userType) {
        return USER_TYPE_PROFILE_COMMUNAL.equals(userType);
    }

    /**
    /**
     * @hide
     * @hide
     * @deprecated Use {@link #isRestrictedProfile()}
     * @deprecated Use {@link #isRestrictedProfile()}
@@ -2986,6 +3043,7 @@ public class UserManager {
     *   <li>(Running) profiles of the current foreground user.
     *   <li>(Running) profiles of the current foreground user.
     *   <li>Background users assigned to secondary displays (for example, passenger users on
     *   <li>Background users assigned to secondary displays (for example, passenger users on
     *   automotive builds, using the display associated with their seats).
     *   automotive builds, using the display associated with their seats).
     *   <li>A communal profile, if present.
     * </ol>
     * </ol>
     *
     *
     * @return whether the user is visible at the moment, as defined above.
     * @return whether the user is visible at the moment, as defined above.
Loading