diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java index 4d9c17693fab9..cbd2f7850657b 100644 --- a/core/java/android/content/pm/UserInfo.java +++ b/core/java/android/content/pm/UserInfo.java @@ -20,6 +20,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.SystemProperties; import android.os.UserHandle; +import android.os.UserManager; /** * Per-user information. @@ -135,6 +136,15 @@ public class UserInfo implements Parcelable { return !isManagedProfile() || SystemProperties.getBoolean("fw.show_hidden_users", false); } + /** + * @return true if this user can be switched to by end user through UI. + */ + public boolean supportsSwitchToByUser() { + // Hide the system user when it does not represent a human user. + boolean hideSystemUser = UserManager.isSplitSystemUser(); + return (!hideSystemUser || id != UserHandle.USER_SYSTEM) && supportsSwitchTo(); + } + public UserInfo() { } diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index a43cf5af22528..0192ef514e1c6 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -15,6 +15,7 @@ */ package android.os; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.app.ActivityManager; import android.app.ActivityManagerNative; @@ -521,6 +522,16 @@ public class UserManager { Resources.getSystem().getBoolean(R.bool.config_enableMultiUserUI)); } + /** + * @hide + * @return Whether the device is running with split system user. It means the system user and + * primary user are two separate users. Previously system user and primary user are combined as + * a single owner user. see @link {android.os.UserHandle#USER_OWNER} + */ + public static boolean isSplitSystemUser() { + return SystemProperties.getBoolean("ro.fw.system_user_split", false); + } + /** * Returns the user handle for the user that this process is running under. * @@ -986,7 +997,7 @@ public class UserManager { * @return the Primary user, null if not found. * @hide */ - public UserInfo getPrimaryUser() { + public @Nullable UserInfo getPrimaryUser() { try { return mService.getPrimaryUser(); } catch (RemoteException re) { @@ -1293,7 +1304,7 @@ public class UserManager { } int switchableUserCount = 0; for (UserInfo user : users) { - if (user.supportsSwitchTo()) { + if (user.supportsSwitchToByUser()) { ++switchableUserCount; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index 41fc967de14d0..eec91dbb81298 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -79,7 +79,7 @@ public class UserSwitcherController { private ArrayList mUsers = new ArrayList<>(); private Dialog mExitGuestDialog; private Dialog mAddUserDialog; - private int mLastNonGuestUser = UserHandle.USER_OWNER; + private int mLastNonGuestUser = UserHandle.USER_SYSTEM; private boolean mSimpleUserSwitcher; private boolean mAddUsersWhenLocked; @@ -95,7 +95,7 @@ public class UserSwitcherController { filter.addAction(Intent.ACTION_USER_SWITCHED); filter.addAction(Intent.ACTION_USER_STOPPING); filter.addAction(ACTION_REMOVE_GUEST); - mContext.registerReceiverAsUser(mReceiver, UserHandle.OWNER, filter, + mContext.registerReceiverAsUser(mReceiver, UserHandle.SYSTEM, filter, null /* permission */, null /* scheduler */); @@ -146,17 +146,21 @@ public class UserSwitcherController { } ArrayList records = new ArrayList<>(infos.size()); int currentId = ActivityManager.getCurrentUser(); + UserInfo currentUserInfo = null; UserRecord guestRecord = null; int avatarSize = mContext.getResources() .getDimensionPixelSize(R.dimen.max_avatar_size); for (UserInfo info : infos) { boolean isCurrent = currentId == info.id; + if (isCurrent) { + currentUserInfo = info; + } if (info.isGuest()) { guestRecord = new UserRecord(info, null /* picture */, true /* isGuest */, isCurrent, false /* isAddUser */, false /* isRestricted */); - } else if (info.supportsSwitchTo()) { + } else if (info.supportsSwitchToByUser()) { Bitmap picture = bitmaps.get(info.id); if (picture == null) { picture = mUserManager.getUserIcon(info.id); @@ -172,11 +176,13 @@ public class UserSwitcherController { } } - boolean ownerCanCreateUsers = !mUserManager.hasUserRestriction( - UserManager.DISALLOW_ADD_USER, UserHandle.OWNER); - boolean currentUserCanCreateUsers = - (currentId == UserHandle.USER_OWNER) && ownerCanCreateUsers; - boolean anyoneCanCreateUsers = ownerCanCreateUsers && addUsersWhenLocked; + boolean systemCanCreateUsers = !mUserManager.hasUserRestriction( + UserManager.DISALLOW_ADD_USER, UserHandle.SYSTEM); + boolean currentUserCanCreateUsers = currentUserInfo != null + && (currentUserInfo.isAdmin() + || currentUserInfo.id == UserHandle.USER_SYSTEM) + && systemCanCreateUsers; + boolean anyoneCanCreateUsers = systemCanCreateUsers && addUsersWhenLocked; boolean canCreateGuest = (currentUserCanCreateUsers || anyoneCanCreateUsers) && guestRecord == null; boolean canCreateUser = (currentUserCanCreateUsers || anyoneCanCreateUsers) @@ -284,10 +290,10 @@ public class UserSwitcherController { } private void exitGuest(int id) { - int newId = UserHandle.USER_OWNER; - if (mLastNonGuestUser != UserHandle.USER_OWNER) { + int newId = UserHandle.USER_SYSTEM; + if (mLastNonGuestUser != UserHandle.USER_SYSTEM) { UserInfo info = mUserManager.getUserInfo(mLastNonGuestUser); - if (info != null && info.isEnabled() && info.supportsSwitchTo()) { + if (info != null && info.isEnabled() && info.supportsSwitchToByUser()) { newId = info.id; } } @@ -325,6 +331,7 @@ public class UserSwitcherController { } final int currentId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); + final UserInfo userInfo = mUserManager.getUserInfo(currentId); final int N = mUsers.size(); for (int i = 0; i < N; i++) { UserRecord record = mUsers.get(i); @@ -336,7 +343,7 @@ public class UserSwitcherController { if (shouldBeCurrent && !record.isGuest) { mLastNonGuestUser = record.info.id; } - if (currentId != UserHandle.USER_OWNER && record.isRestricted) { + if ((userInfo == null || !userInfo.isAdmin()) && record.isRestricted) { // Immediately remove restricted records in case the AsyncTask is too slow. mUsers.remove(i); i--; @@ -354,7 +361,7 @@ public class UserSwitcherController { private void showGuestNotification(int guestUserId) { PendingIntent removeGuestPI = PendingIntent.getBroadcastAsUser(mContext, - 0, new Intent(ACTION_REMOVE_GUEST), 0, UserHandle.OWNER); + 0, new Intent(ACTION_REMOVE_GUEST), 0, UserHandle.SYSTEM); Notification notification = new Notification.Builder(mContext) .setVisibility(Notification.VISIBILITY_SECRET) .setPriority(Notification.PRIORITY_MIN) diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java index 3cee9279c018b..d160221f5cc46 100644 --- a/services/core/java/com/android/server/policy/GlobalActions.java +++ b/services/core/java/com/android/server/policy/GlobalActions.java @@ -534,7 +534,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac List users = um.getUsers(); UserInfo currentUser = getCurrentUser(); for (final UserInfo user : users) { - if (user.supportsSwitchTo()) { + if (user.supportsSwitchToByUser()) { boolean isCurrentUser = currentUser == null ? user.id == 0 : (currentUser.id == user.id); Drawable icon = user.iconPath != null ? Drawable.createFromPath(user.iconPath) diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index 15da8290ae407..07fc23fc395b0 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -227,7 +227,7 @@ public class TrustManagerService extends SystemService { for (UserInfo userInfo : userInfos) { if (userInfo == null || userInfo.partial || !userInfo.isEnabled() || userInfo.guestToRemove) continue; - if (!userInfo.supportsSwitchTo()) continue; + if (!userInfo.supportsSwitchToByUser()) continue; if (!mActivityManager.isUserRunning(userInfo.id)) continue; if (!lockPatternUtils.isSecure(userInfo.id)) continue; if (!getUserHasAuthenticated(userInfo.id)) continue; @@ -316,7 +316,7 @@ public class TrustManagerService extends SystemService { UserInfo info = userInfos.get(i); if (info == null || info.partial || !info.isEnabled() || info.guestToRemove - || !info.supportsSwitchTo()) { + || !info.supportsSwitchToByUser()) { continue; } @@ -783,7 +783,7 @@ public class TrustManagerService extends SystemService { private void dumpUser(PrintWriter fout, UserInfo user, boolean isCurrent) { fout.printf(" User \"%s\" (id=%d, flags=%#x)", user.name, user.id, user.flags); - if (!user.supportsSwitchTo()) { + if (!user.supportsSwitchToByUser()) { fout.println("(managed profile)"); fout.println(" disabled because switching to this user is not possible."); return;