sys user split: refactor systemui user switcher

BUG:19913735
Change-Id: I017dd1b03fd163c266b8080b969fb7a2e934e26c
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 4d9c176..cbd2f78 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -20,6 +20,7 @@
 import android.os.Parcelable;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.os.UserManager;
 
 /**
  * Per-user information.
@@ -135,6 +136,15 @@
         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 a43cf5a..0192ef5 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;
@@ -522,6 +523,16 @@
     }
 
     /**
+     * @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.
      *
      * @return the user handle of this process.
@@ -986,7 +997,7 @@
      * @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 @@
         }
         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 41fc967..eec91db 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 @@
     private ArrayList<UserRecord> 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 @@
         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 @@
                 }
                 ArrayList<UserRecord> 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 @@
                     }
                 }
 
-                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 @@
     }
 
     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 @@
                 }
 
                 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 @@
                     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 @@
 
         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 3cee927..d160221f 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 @@
             List<UserInfo> 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 15da829..07fc23f 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 @@
         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 @@
             UserInfo info = userInfos.get(i);
 
             if (info == null || info.partial || !info.isEnabled() || info.guestToRemove
-                    || !info.supportsSwitchTo()) {
+                    || !info.supportsSwitchToByUser()) {
                 continue;
             }
 
@@ -783,7 +783,7 @@
         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;