add support for guest user

Bug: 135057192
Bug: 130661989
Test: tapas tradefed-all && make && \
    tools/tradefederation/core/tradefed.sh run singleCommand host -n \
    --class com.android.tradefed.UnitTests
Change-Id: I2b9469dfd4d2634df4f00784537e9e67f2174ac3
Merged-In: I2b9469dfd4d2634df4f00784537e9e67f2174ac3
diff --git a/src/com/android/tradefed/device/UserInfo.java b/src/com/android/tradefed/device/UserInfo.java
index b37ef1b..4cccbbb 100644
--- a/src/com/android/tradefed/device/UserInfo.java
+++ b/src/com/android/tradefed/device/UserInfo.java
@@ -42,12 +42,36 @@
     public enum UserType {
         /** current foreground user of the device */
         CURRENT,
+        /**
+         * guest user. Only one can exist at a time, may be ephemeral and have more restrictions.
+         */
+        GUEST,
         /** user flagged as primary on the device; most often primary = system user = user 0 */
         PRIMARY,
         /** system user = user 0 */
         SYSTEM,
         /** secondary user, i.e. non-primary and non-system. */
         SECONDARY;
+
+        public boolean isCurrent() {
+            return this == CURRENT;
+        }
+
+        public boolean isGuest() {
+            return this == GUEST;
+        }
+
+        public boolean isPrimary() {
+            return this == PRIMARY;
+        }
+
+        public boolean isSystem() {
+            return this == SYSTEM;
+        }
+
+        public boolean isSecondary() {
+            return this == SECONDARY;
+        }
     }
 
     public UserInfo(int userId, String userName, int flag, boolean isRunning) {
@@ -73,6 +97,10 @@
         return mIsRunning;
     }
 
+    public boolean isGuest() {
+        return (mFlag & FLAG_GUEST) == FLAG_GUEST;
+    }
+
     public boolean isPrimary() {
         return (mFlag & FLAG_PRIMARY) == FLAG_PRIMARY;
     }
@@ -90,6 +118,8 @@
         switch (userType) {
             case CURRENT:
                 return mUserId == currentUserId;
+            case GUEST:
+                return isGuest();
             case PRIMARY:
                 return isPrimary();
             case SYSTEM:
diff --git a/src/com/android/tradefed/suite/checker/UserChecker.java b/src/com/android/tradefed/suite/checker/UserChecker.java
index 3448fd7..8c2841a 100644
--- a/src/com/android/tradefed/suite/checker/UserChecker.java
+++ b/src/com/android/tradefed/suite/checker/UserChecker.java
@@ -64,7 +64,7 @@
             mSwitchedToUserId =
                     device.createUser(
                             /* name= */ "Tf" + mUserToSwitchTo.toString().toLowerCase(),
-                            /* guest= */ false,
+                            /* guest= */ mUserToSwitchTo.isGuest(),
                             /* ephemeral= */ false);
             CLog.i(
                     "No user of type %s found, created user %d",
diff --git a/tests/src/com/android/tradefed/suite/checker/UserCheckerTest.java b/tests/src/com/android/tradefed/suite/checker/UserCheckerTest.java
index 79cc86e..5b73842 100644
--- a/tests/src/com/android/tradefed/suite/checker/UserCheckerTest.java
+++ b/tests/src/com/android/tradefed/suite/checker/UserCheckerTest.java
@@ -184,6 +184,26 @@
     }
 
     @Test
+    public void testSwitchToGuest() throws Exception {
+        UserChecker checker = new UserChecker();
+        OptionSetter mOptionSetter = new OptionSetter(checker);
+        mOptionSetter.setOptionValue("user-type", "guest");
+        ITestDevice device =
+                mockDeviceUserState(
+                        /* currentUser=  */ 0,
+                        /* userIds= */ new Integer[] {0, 10},
+                        /* flags=        */ new Integer[] {0, UserInfo.FLAG_GUEST},
+                        /* isRunning= */ new Boolean[] {true, false});
+
+        when(device.switchUser(10)).thenReturn(true);
+
+        StatusCheckerResult result = checker.preExecutionCheck(device);
+        assertEquals(CheckStatus.SUCCESS, result.getStatus());
+        verify(device, never()).createUser(any(), anyBoolean(), anyBoolean());
+        verify(device, times(1)).switchUser(10);
+    }
+
+    @Test
     public void testCreateSecondary() throws Exception {
         UserChecker checker = new UserChecker();
         OptionSetter mOptionSetter = new OptionSetter(checker);
@@ -200,6 +220,24 @@
         verify(device, times(1)).switchUser(10);
     }
 
+    @Test
+    public void testCreateGuest() throws Exception {
+        UserChecker checker = new UserChecker();
+        OptionSetter mOptionSetter = new OptionSetter(checker);
+        mOptionSetter.setOptionValue("user-type", "guest");
+        ITestDevice device =
+                mockDeviceUserState(/* currentUser=  */ 0, /* userIds= */ new Integer[] {0});
+
+        when(device.createUser("Tfguest", /* guest= */ true, /* ephemeral= */ false))
+                .thenReturn(10);
+        when(device.switchUser(10)).thenReturn(true);
+
+        StatusCheckerResult result = checker.preExecutionCheck(device);
+        assertEquals(CheckStatus.SUCCESS, result.getStatus());
+        verify(device, times(1)).createUser("Tfguest", /* guest= */ true, /* ephemeral= */ false);
+        verify(device, times(1)).switchUser(10);
+    }
+
     // // TEST HELPERS
 
     /** Return a device with the user state calls mocked. */
diff --git a/tests/src/com/android/tradefed/targetprep/SwitchUserTargetPreparerTest.java b/tests/src/com/android/tradefed/targetprep/SwitchUserTargetPreparerTest.java
index 2aee830..4959f73 100644
--- a/tests/src/com/android/tradefed/targetprep/SwitchUserTargetPreparerTest.java
+++ b/tests/src/com/android/tradefed/targetprep/SwitchUserTargetPreparerTest.java
@@ -57,7 +57,7 @@
     }
 
     @Test
-    public void testSetUpRunAsPrimary_ifAlreadyInPrimary()
+    public void testSetUpRunAsPrimary_ifAlreadyInPrimary_noSwitch()
             throws DeviceNotAvailableException, TargetSetupError, ConfigurationException {
         mOptionSetter.setOptionValue("user-type", "primary");
 
@@ -76,23 +76,22 @@
     }
 
     @Test
-    public void testSetUpRunAsSystem_ifAlreadyInSystem_switchToSystem()
+    public void testSetUpRunAsSystem_ifAlreadyInSystem_noSwitch()
             throws DeviceNotAvailableException, TargetSetupError, ConfigurationException {
         mOptionSetter.setOptionValue("user-type", "system");
 
         // setup
-        when(mMockDevice.getCurrentUser()).thenReturn(11);
+        when(mMockDevice.getCurrentUser()).thenReturn(0);
         mockListUsersInfo(
                 mMockDevice,
                 /* userIds= */ new Integer[] {0, 11},
                 /* flags= */ new Integer[] {0, UserInfo.FLAG_PRIMARY});
-        when(mMockDevice.switchUser(0)).thenReturn(true);
 
         // act
         mSwitchUserTargetPreparer.setUp(mMockDevice, /* buildInfo= */ null);
 
         // assert
-        verify(mMockDevice, times(1)).switchUser(0);
+        verify(mMockDevice, never()).switchUser(0);
     }
 
     @Test
@@ -116,6 +115,26 @@
     }
 
     @Test
+    public void testSetUpRunAsGuest_ifNotInGuest_switchToGuest()
+            throws DeviceNotAvailableException, TargetSetupError, ConfigurationException {
+        mOptionSetter.setOptionValue("user-type", "guest");
+
+        // setup
+        when(mMockDevice.getCurrentUser()).thenReturn(11);
+        mockListUsersInfo(
+                mMockDevice,
+                /* userIds= */ new Integer[] {0, 10, 11},
+                /* flags= */ new Integer[] {0, UserInfo.FLAG_GUEST, 0});
+        when(mMockDevice.switchUser(10)).thenReturn(true);
+
+        // act
+        mSwitchUserTargetPreparer.setUp(mMockDevice, /* buildInfo= */ null);
+
+        // assert
+        verify(mMockDevice, times(1)).switchUser(10);
+    }
+
+    @Test
     public void testSetUpRunAsSystem_ifNotInSystem_switchToSystem()
             throws DeviceNotAvailableException, TargetSetupError, ConfigurationException {
         mOptionSetter.setOptionValue("user-type", "system");