Add a flag to protect headless user 0 multi-user model.

Test: unit test
Bug: 80305146
Change-Id: Ibb029072756e29b57c747152bb779a1037aca753
diff --git a/car-lib/src/android/car/user/CarUserManagerHelper.java b/car-lib/src/android/car/user/CarUserManagerHelper.java
index ece0ac2..45d2c7f 100644
--- a/car-lib/src/android/car/user/CarUserManagerHelper.java
+++ b/car-lib/src/android/car/user/CarUserManagerHelper.java
@@ -25,6 +25,7 @@
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Log;
@@ -46,6 +47,7 @@
  */
 public class CarUserManagerHelper {
     private static final String TAG = "CarUserManagerHelper";
+    private static final String HEADLESS_SYSTEM_USER = "android.car.systemuser.headless";
     private final Context mContext;
     private final UserManager mUserManager;
     private final ActivityManager mActivityManager;
@@ -88,6 +90,15 @@
     }
 
     /**
+     * Returns {@code true} if the system is in the headless user 0 model.
+     *
+     * @return {@boolean true} if headless system user.
+     */
+    public boolean isHeadlessSystemUser() {
+        return SystemProperties.getBoolean(HEADLESS_SYSTEM_USER, false);
+    }
+
+    /**
      * Gets UserInfo for the system user.
      *
      * @return {@link UserInfo} for the system user.
@@ -145,7 +156,11 @@
      * @return List of {@code UserInfo} for each user that is not the foreground user.
      */
     public List<UserInfo> getAllSwitchableUsers() {
-        return getAllUsersExceptSystemUserAndSpecifiedUser(getCurrentForegroundUserId());
+        if (isHeadlessSystemUser()) {
+            return getAllUsersExceptSystemUserAndSpecifiedUser(getCurrentForegroundUserId());
+        } else {
+            return getAllUsersExceptSpecifiedUser(getCurrentForegroundUserId());
+        }
     }
 
     /**
@@ -154,7 +169,11 @@
      * @return List of {@code UserInfo} for users that associated with a real person.
      */
     public List<UserInfo> getAllUsers() {
-        return getAllUsersExceptSystemUserAndSpecifiedUser(UserHandle.USER_SYSTEM);
+        if (isHeadlessSystemUser()) {
+            return getAllUsersExceptSystemUserAndSpecifiedUser(UserHandle.USER_SYSTEM);
+        } else {
+            return mUserManager.getUsers(/* excludeDying= */true);
+        }
     }
 
     /**
@@ -163,17 +182,36 @@
      * @return List of {@code UserInfo} for users that associated with a real person.
      */
     public List<UserInfo> getAllUsersIncludingSystemUser() {
-        return mUserManager.getUsers(/*excludeDying=*/true);
+        return mUserManager.getUsers(/* excludeDying= */true);
+    }
+
+    /**
+     * Get all the users except the one with userId passed in.
+     *
+     * @param userId of the user not to be returned.
+     * @return All users other than user with userId.
+     */
+    private List<UserInfo> getAllUsersExceptSpecifiedUser(int userId) {
+        List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
+
+        for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
+            UserInfo userInfo = iterator.next();
+            if (userInfo.id == userId) {
+                // Remove user with userId from the list.
+                iterator.remove();
+            }
+        }
+        return users;
     }
 
     /**
      * Get all the users except system user and the one with userId passed in.
      *
      * @param userId of the user not to be returned.
-     * @return All users other than user with userId.
+     * @return All users other than system user and user with userId.
      */
     private List<UserInfo> getAllUsersExceptSystemUserAndSpecifiedUser(int userId) {
-        List<UserInfo> users = mUserManager.getUsers(/*excludeDying=*/true);
+        List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
 
         for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
             UserInfo userInfo = iterator.next();
@@ -380,6 +418,20 @@
     }
 
     /**
+     * Switches (logs in) to another user given user id.
+     *
+     * @param id User id to switch to.
+     * @return {@code true} if user switching succeed.
+     */
+    public boolean switchToUserId(int id) {
+        if (id == UserHandle.USER_SYSTEM && isHeadlessSystemUser()) {
+            // System User doesn't associate with real person, can not be switched to.
+            return false;
+        }
+        return mActivityManager.switchUser(id);
+    }
+
+    /**
      * Switches (logs in) to another user.
      *
      * @param userInfo User to switch to.
@@ -493,14 +545,6 @@
         return bitmap;
     }
 
-    private boolean switchToUserId(int id) {
-        if (id == UserHandle.USER_SYSTEM) {
-            // System User doesn't associate with real person, can not be switched to.
-            return false;
-        }
-        return mActivityManager.switchUser(id);
-    }
-
     private void unregisterReceiver() {
         mContext.unregisterReceiver(mUserChangeReceiver);
     }
diff --git a/tests/carservice_unit_test/src/com/android/car/CarUserManagerTest.java b/tests/carservice_unit_test/src/com/android/car/CarUserManagerHelperTest.java
similarity index 91%
rename from tests/carservice_unit_test/src/com/android/car/CarUserManagerTest.java
rename to tests/carservice_unit_test/src/com/android/car/CarUserManagerHelperTest.java
index ff24b8e..3d9cce6 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarUserManagerTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarUserManagerHelperTest.java
@@ -31,6 +31,7 @@
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.support.test.InstrumentationRegistry;
@@ -57,7 +58,7 @@
  * 4. {@link CarUserManagerHelper.OnUsersUpdateListener} registers a listener for user updates.
  */
 @RunWith(AndroidJUnit4.class)
-public class CarUserManagerTest {
+public class CarUserManagerHelperTest {
     @Mock
     private Context mContext;
     @Mock
@@ -101,7 +102,8 @@
 
     // System user will not be returned when calling get all users.
     @Test
-    public void testGetAllUsers_NotReturnSystemUser() {
+    public void testHeadlessUser0GetAllUsers_NotReturnSystemUser() {
+        SystemProperties.set("android.car.systemuser.headless", "true");
         UserInfo otherUser1 = createUserInfoForId(10);
         UserInfo otherUser2 = createUserInfoForId(11);
         UserInfo otherUser3 = createUserInfoForId(12);
@@ -121,7 +123,8 @@
     }
 
     @Test
-    public void testGetAllUsersWithActiveForegroundUser_NotReturnSystemUser() {
+    public void testHeadlessUser0GetAllUsersWithActiveForegroundUser_NotReturnSystemUser() {
+        SystemProperties.set("android.car.systemuser.headless", "true");
         mCurrentProcessUser = createUserInfoForId(10);
 
         UserInfo otherUser1 = createUserInfoForId(11);
@@ -142,7 +145,6 @@
             .containsExactly(mCurrentProcessUser, otherUser1, otherUser2, otherUser3);
     }
 
-    // Get all users should exclude system user by default.
     @Test
     public void testGetAllSwitchableUsers() {
         UserInfo user1 = createUserInfoForId(10);
@@ -170,6 +172,30 @@
         assertThat(mHelper.getAllSwitchableUsers()).contains(user3);
     }
 
+    // Get all users for headless user 0 model should exclude system user by default.
+    @Test
+    public void testHeadlessUser0GetAllSwitchableUsers() {
+        SystemProperties.set("android.car.systemuser.headless", "true");
+        UserInfo user1 = createUserInfoForId(10);
+        UserInfo user2 = createUserInfoForId(11);
+        UserInfo user3 = createUserInfoForId(12);
+
+        List<UserInfo> testUsers = new ArrayList<>();
+        testUsers.add(mSystemUser);
+        testUsers.add(user1);
+        testUsers.add(user2);
+        testUsers.add(user3);
+
+        when(mUserManager.getUsers(true)).thenReturn(new ArrayList<>(testUsers));
+
+        // Should return all 3 non-system users.
+        assertThat(mHelper.getAllUsers()).hasSize(3);
+
+        when(mUserManager.getUserInfo(UserHandle.myUserId())).thenReturn(user1);
+        // Should return user 10, 11 and 12.
+        assertThat(mHelper.getAllSwitchableUsers()).containsExactly(user1, user2, user3);
+    }
+
     @Test
     public void testUserCanBeRemoved() {
         UserInfo testInfo = new UserInfo();
diff --git a/tests/robotests/src/com/android/car/users/CarUserManagerRoboTest.java b/tests/robotests/src/com/android/car/users/CarUserManagerHelperRoboTest.java
similarity index 93%
rename from tests/robotests/src/com/android/car/users/CarUserManagerRoboTest.java
rename to tests/robotests/src/com/android/car/users/CarUserManagerHelperRoboTest.java
index 977ee7c..9c39445 100644
--- a/tests/robotests/src/com/android/car/users/CarUserManagerRoboTest.java
+++ b/tests/robotests/src/com/android/car/users/CarUserManagerHelperRoboTest.java
@@ -43,7 +43,7 @@
 @RunWith(CarServiceRobolectricTestRunner.class)
 @Config(shadows = { ShadowActivityManager.class,
         ShadowUserHandle.class, ShadowUserManager.class})
-public class CarUserManagerRoboTest {
+public class CarUserManagerHelperRoboTest {
     @Mock
     private Context mContext;
 
@@ -95,7 +95,7 @@
     }
 
     @Test
-    public void testGetAllUsersExcludesCurrentProcessUser() {
+    public void testGetAllUsers() {
         int currentProcessUserId = 12;
         ShadowUserManager userManager = ShadowUserManager.getShadow();
         userManager.setCurrentUser(currentProcessUserId);
@@ -111,10 +111,14 @@
         userManager.addUserInfo(otherUser1);
         userManager.addUserInfo(otherUser2);
 
-        // Should return 3 users that don't have currentProcessUser id.
-        assertThat(mHelper.getAllUsers()).hasSize(3);
-        assertThat(mHelper.getAllUsers())
-            .containsExactly(currentProcessUser, otherUser1, otherUser2);
+        if (mHelper.isHeadlessSystemUser()) {
+            // Should return 3 users that don't have system user id.
+            assertThat(mHelper.getAllUsers())
+                .containsExactly(currentProcessUser, otherUser1, otherUser2);
+        } else {
+            assertThat(mHelper.getAllUsers())
+                .containsExactly(systemUser, currentProcessUser, otherUser1, otherUser2);
+        }
     }
 
     @Test