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

Commit c59305fb authored by Oli Lan's avatar Oli Lan
Browse files

Add system API to get the previous user.

This adds a system API to retrieve the user that was last in the
foreground, apart from the current user.

This may be used for example when the current user is removed,
to switch to the previous current user.

Bug: 259373662
Test: atest UserManagerHostTest
Change-Id: Ie21fe2f47a90633d2e2a9cb36f03d7d1bca1f9d5
parent 28bd0458
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -10050,6 +10050,7 @@ package android.os {
    method @NonNull public java.util.List<android.os.UserHandle> getAllProfiles();
    method @NonNull public java.util.List<android.os.UserHandle> getEnabledProfiles();
    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public android.os.UserHandle getMainUser();
    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public android.os.UserHandle getPreviousForegroundUser();
    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public android.os.UserHandle getProfileParent(@NonNull android.os.UserHandle);
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public int getRemainingCreatableProfileCount(@NonNull String);
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public int getRemainingCreatableUserCount(@NonNull String);
+1 −0
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ interface IUserManager {
    ParcelFileDescriptor getUserIcon(int userId);
    UserInfo getPrimaryUser();
    int getMainUserId();
    int getPreviousFullUserToEnterForeground();
    List<UserInfo> getUsers(boolean excludePartial, boolean excludeDying, boolean excludePreCreated);
    List<UserInfo> getProfiles(int userId, boolean enabledOnly);
    int[] getProfileIds(int userId, boolean enabledOnly);
+37 −0
Original line number Diff line number Diff line
@@ -4299,6 +4299,43 @@ public class UserManager {
        }
    }

    /**
     * Returns the user who was last in the foreground, not including the current user and not
     * including profiles.
     *
     * <p>Returns {@code null} if there is no previous user, for example if there
     * is only one full user (i.e. only one user which is not a profile) on the device.
     *
     * <p>This method may be used for example to find the user to switch back to if the
     * current user is removed, or if creating a new user is aborted.
     *
     * <p>Note that reboots do not interrupt this calculation; the previous user need not have
     * used the device since it rebooted.
     *
     * <p>Note also that on devices that support multiple users on multiple displays, it is possible
     * that the returned user will be visible on a secondary display, as the foreground user is the
     * one associated with the main display.
     *
     * @hide
     */
    @SystemApi
    @RequiresPermission(anyOf = {
            android.Manifest.permission.MANAGE_USERS,
            android.Manifest.permission.CREATE_USERS,
            android.Manifest.permission.QUERY_USERS
    })
    public @Nullable UserHandle getPreviousForegroundUser() {
        try {
            final int previousUser = mService.getPreviousFullUserToEnterForeground();
            if (previousUser == UserHandle.USER_NULL) {
                return null;
            }
            return UserHandle.of(previousUser);
        } catch (RemoteException re) {
            throw re.rethrowFromSystemServer();
        }
    }

    /**
     * Checks whether it's possible to add more users.
     *
+56 −0
Original line number Diff line number Diff line
@@ -191,6 +191,7 @@ public class UserManagerService extends IUserManager.Stub {
    private static final String ATTR_CREATION_TIME = "created";
    private static final String ATTR_LAST_LOGGED_IN_TIME = "lastLoggedIn";
    private static final String ATTR_LAST_LOGGED_IN_FINGERPRINT = "lastLoggedInFingerprint";
    private static final String ATTR_LAST_ENTERED_FOREGROUND_TIME = "lastEnteredForeground";
    private static final String ATTR_SERIAL_NO = "serialNumber";
    private static final String ATTR_NEXT_SERIAL_NO = "nextSerialNumber";
    private static final String ATTR_PARTIAL = "partial";
@@ -341,6 +342,9 @@ public class UserManagerService extends IUserManager.Stub {
        /** Elapsed realtime since boot when the user was unlocked. */
        long unlockRealtime;

        /** Wall clock time in millis when the user last entered the foreground. */
        long mLastEnteredForegroundTimeMillis;

        private long mLastRequestQuietModeEnabledMillis;

        /**
@@ -680,6 +684,10 @@ public class UserManagerService extends IUserManager.Stub {
                final UserData user = mUms.getUserDataLU(targetUser.getUserIdentifier());
                if (user != null) {
                    user.startRealtime = SystemClock.elapsedRealtime();
                    if (targetUser.getUserIdentifier() == UserHandle.USER_SYSTEM
                            && targetUser.isFull()) {
                        mUms.setLastEnteredForegroundTimeToNow(user);
                    }
                }
            }
        }
@@ -694,6 +702,16 @@ public class UserManagerService extends IUserManager.Stub {
            }
        }

        @Override
        public void onUserSwitching(@NonNull TargetUser from, @NonNull TargetUser to) {
            synchronized (mUms.mUsersLock) {
                final UserData user = mUms.getUserDataLU(to.getUserIdentifier());
                if (user != null) {
                    mUms.setLastEnteredForegroundTimeToNow(user);
                }
            }
        }

        @Override
        public void onUserStopping(@NonNull TargetUser targetUser) {
            synchronized (mUms.mUsersLock) {
@@ -920,6 +938,30 @@ public class UserManagerService extends IUserManager.Stub {
        return UserHandle.USER_NULL;
    }

    @Override
    public int getPreviousFullUserToEnterForeground() {
        checkQueryOrCreateUsersPermission("get previous user");
        int previousUser = UserHandle.USER_NULL;
        long latestEnteredTime = 0;
        final int currentUser = getCurrentUserId();
        synchronized (mUsersLock) {
            final int userSize = mUsers.size();
            for (int i = 0; i < userSize; i++) {
                final UserData userData = mUsers.valueAt(i);
                final int userId = userData.info.id;
                if (userId != currentUser && userData.info.isFull() && !userData.info.partial
                        && !mRemovingUserIds.get(userId)) {
                    final long userEnteredTime = userData.mLastEnteredForegroundTimeMillis;
                    if (userEnteredTime > latestEnteredTime) {
                        latestEnteredTime = userEnteredTime;
                        previousUser = userId;
                    }
                }
            }
        }
        return previousUser;
    }

    public @NonNull List<UserInfo> getUsers(boolean excludeDying) {
        return getUsers(/*excludePartial= */ true, excludeDying, /* excludePreCreated= */
                true);
@@ -3941,6 +3983,8 @@ public class UserManagerService extends IUserManager.Stub {
            serializer.attribute(null, ATTR_LAST_LOGGED_IN_FINGERPRINT,
                    userInfo.lastLoggedInFingerprint);
        }
        serializer.attributeLong(
                null, ATTR_LAST_ENTERED_FOREGROUND_TIME, userData.mLastEnteredForegroundTimeMillis);
        if (userInfo.iconPath != null) {
            serializer.attribute(null,  ATTR_ICON_PATH, userInfo.iconPath);
        }
@@ -4114,6 +4158,7 @@ public class UserManagerService extends IUserManager.Stub {
        long lastLoggedInTime = 0L;
        long lastRequestQuietModeEnabledTimestamp = 0L;
        String lastLoggedInFingerprint = null;
        long lastEnteredForegroundTime = 0L;
        int profileGroupId = UserInfo.NO_PROFILE_GROUP_ID;
        int profileBadge = 0;
        int restrictedProfileParentId = UserInfo.NO_PROFILE_GROUP_ID;
@@ -4159,6 +4204,8 @@ public class UserManagerService extends IUserManager.Stub {
            lastLoggedInTime = parser.getAttributeLong(null, ATTR_LAST_LOGGED_IN_TIME, 0);
            lastLoggedInFingerprint = parser.getAttributeValue(null,
                    ATTR_LAST_LOGGED_IN_FINGERPRINT);
            lastEnteredForegroundTime =
                    parser.getAttributeLong(null, ATTR_LAST_ENTERED_FOREGROUND_TIME, 0L);
            profileGroupId = parser.getAttributeInt(null, ATTR_PROFILE_GROUP_ID,
                    UserInfo.NO_PROFILE_GROUP_ID);
            profileBadge = parser.getAttributeInt(null, ATTR_PROFILE_BADGE, 0);
@@ -4253,6 +4300,7 @@ public class UserManagerService extends IUserManager.Stub {
        userData.seedAccountOptions = seedAccountOptions;
        userData.userProperties = userProperties;
        userData.setLastRequestQuietModeEnabledMillis(lastRequestQuietModeEnabledTimestamp);
        userData.mLastEnteredForegroundTimeMillis = lastEnteredForegroundTime;
        if (ignorePrepareStorageErrors) {
            userData.setIgnorePrepareStorageErrors();
        }
@@ -6172,6 +6220,11 @@ public class UserManagerService extends IUserManager.Stub {
                        || someUserHasSeedAccountNoChecks(accountName, accountType));
    }

    private void setLastEnteredForegroundTimeToNow(@NonNull UserData userData) {
        userData.mLastEnteredForegroundTimeMillis = System.currentTimeMillis();
        scheduleWriteUser(userData);
    }

    @Override
    public void onShellCommand(FileDescriptor in, FileDescriptor out,
            FileDescriptor err, String[] args, ShellCallback callback,
@@ -6396,6 +6449,9 @@ public class UserManagerService extends IUserManager.Stub {
        pw.print("    Unlock time: ");
        dumpTimeAgo(pw, tempStringBuilder, nowRealtime, userData.unlockRealtime);

        pw.print("    Last entered foreground: ");
        dumpTimeAgo(pw, tempStringBuilder, now, userData.mLastEnteredForegroundTimeMillis);

        pw.print("    Has profile owner: ");
        pw.println(mIsUserManaged.get(userId));
        pw.println("    Restrictions:");