Changes on am / cmd user for ITestDevice integration

- Added (optional) listener to startUserInBackgroundVisibleOnDisplay
- Added cmd user is-visible-background-users-supported

It will used by shell command and ITestDevice (which uses the cmd).

Test: adb shell cmd user is-visible-background-users-supported
Test: adb shell am start-user --display 2 -w 10
Test: atest -it com.android.server.am.ActivityManagerServiceTest UserControllerTest

Bug: 266851112

Change-Id: I04648a0ba91ec883273cf519c77b081eabfd5187
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index c4d6ad7..b117bdd 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -4417,7 +4417,8 @@
                     "device does not support users on secondary displays");
         }
         try {
-            return getService().startUserInBackgroundVisibleOnDisplay(userId, displayId);
+            return getService().startUserInBackgroundVisibleOnDisplay(userId, displayId,
+                    /* unlockProgressListener= */ null);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 058c389..d26e6ed 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -803,7 +803,7 @@
      */
     @JavaPassthrough(annotation=
             "@android.annotation.RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional = true)")
-    boolean startUserInBackgroundVisibleOnDisplay(int userid, int displayId);
+    boolean startUserInBackgroundVisibleOnDisplay(int userid, int displayId, IProgressListener unlockProgressListener);
 
     /**
      * Similar to {@link #startProfile(int userId)}, but with a listener to report user unlock
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b272502..b41f506 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -16629,7 +16629,8 @@
     }
 
     @Override
-    public boolean startUserInBackgroundVisibleOnDisplay(int userId, int displayId) {
+    public boolean startUserInBackgroundVisibleOnDisplay(int userId, int displayId,
+            @Nullable IProgressListener unlockListener) {
         int[] displayIds = getDisplayIdsForStartingVisibleBackgroundUsers();
         boolean validDisplay = false;
         if (displayIds != null) {
@@ -16646,11 +16647,11 @@
         }
 
         if (DEBUG_MU) {
-            Slogf.d(TAG_MU, "Calling startUserOnSecondaryDisplay(%d, %d) using injector %s", userId,
-                    displayId, mInjector);
+            Slogf.d(TAG_MU, "Calling startUserOnSecondaryDisplay(%d, %d, %s) using injector %s",
+                    userId, displayId, unlockListener, mInjector);
         }
         // Permission check done inside UserController.
-        return mInjector.startUserInBackgroundVisibleOnDisplay(userId, displayId);
+        return mInjector.startUserInBackgroundVisibleOnDisplay(userId, displayId, unlockListener);
     }
 
     @Override
@@ -19031,8 +19032,10 @@
         /**
          * Called by {@code AMS.startUserInBackgroundVisibleOnDisplay()}.
          */
-        public boolean startUserInBackgroundVisibleOnDisplay(int userId, int displayId) {
-            return mUserController.startUserVisibleOnDisplay(userId, displayId);
+        public boolean startUserInBackgroundVisibleOnDisplay(int userId, int displayId,
+                @Nullable IProgressListener unlockProgressListener) {
+            return mUserController.startUserVisibleOnDisplay(userId, displayId,
+                    unlockProgressListener);
         }
 
         /**
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 3ab1cd7..0f36eb9 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2243,9 +2243,10 @@
                     pw.println("Not supported");
                     return -1;
                 }
-                Slogf.d(TAG, "calling startUserInBackgroundVisibleOnDisplay(%d,%d)", userId,
-                        displayId);
-                success = mInterface.startUserInBackgroundVisibleOnDisplay(userId, displayId);
+                Slogf.d(TAG, "calling startUserInBackgroundVisibleOnDisplay(%d, %d, %s)", userId,
+                        displayId, waiter);
+                success = mInterface.startUserInBackgroundVisibleOnDisplay(userId, displayId,
+                        waiter);
                 displaySuffix = " on display " + displayId;
             }
             if (wait && success) {
@@ -3849,6 +3850,7 @@
 
     int runListDisplaysForStartingUsers(PrintWriter pw) throws RemoteException {
         int[] displayIds = mInterface.getDisplayIdsForStartingVisibleBackgroundUsers();
+        // NOTE: format below cannot be changed as it's used by ITestDevice
         pw.println(displayIds == null || displayIds.length == 0
                 ? "none"
                 : Arrays.toString(displayIds));
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index b2e4740..75f48a7 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1560,16 +1560,18 @@
      *
      * @param userId user to be started
      * @param displayId display where the user will be visible
+     * @param unlockListener Listener to be informed when the user has started and unlocked.
      *
      * @return whether the user was started
      */
-    boolean startUserVisibleOnDisplay(@UserIdInt int userId, int displayId) {
+    boolean startUserVisibleOnDisplay(@UserIdInt int userId, int displayId,
+            @Nullable IProgressListener unlockListener) {
         checkCallingHasOneOfThosePermissions("startUserOnDisplay",
                 MANAGE_USERS, INTERACT_ACROSS_USERS);
 
         try {
             return startUserNoChecks(userId, displayId, USER_START_MODE_BACKGROUND_VISIBLE,
-                    /* unlockListener= */ null);
+                    unlockListener);
         } catch (RuntimeException e) {
             Slogf.e(TAG, "startUserOnSecondaryDisplay(%d, %d) failed: %s", userId, displayId, e);
             return false;
diff --git a/services/core/java/com/android/server/pm/UserManagerServiceShellCommand.java b/services/core/java/com/android/server/pm/UserManagerServiceShellCommand.java
index 50a1d90..165b009 100644
--- a/services/core/java/com/android/server/pm/UserManagerServiceShellCommand.java
+++ b/services/core/java/com/android/server/pm/UserManagerServiceShellCommand.java
@@ -111,6 +111,11 @@
         pw.println("    It returns the effective mode, even when using emulation");
         pw.println("    (to get the real mode as well, use -v or --verbose)");
         pw.println();
+        pw.println("  is-visible-background-users-supported [-v | --verbose]");
+        pw.println("    Checks whether the device allows users to be start visible on background.");
+        pw.println("    It returns the effective mode, even when using emulation");
+        pw.println("    (to get the real mode as well, use -v or --verbose)");
+        pw.println();
         pw.println("  is-user-visible [--display DISPLAY_ID] <USER_ID>");
         pw.println("    Checks if the given user is visible in the given display.");
         pw.println("    If the display option is not set, it uses the user's context to check");
@@ -134,6 +139,8 @@
                     return runSetSystemUserModeEmulation();
                 case "is-headless-system-user-mode":
                     return runIsHeadlessSystemUserMode();
+                case "is-visible-background-users-supported":
+                    return runIsVisibleBackgroundUserSupported();
                 case "is-visible-background-users-on-default-display-supported":
                     return runIsVisibleBackgroundUserOnDefaultDisplaySupported();
                 case "is-user-visible":
@@ -418,6 +425,7 @@
         } else {
             isVisible = getUserManagerForUser(userId).isUserVisible();
         }
+        // NOTE: do not change output below (or command name / args), as it's used by ITestDevice
         pw.println(isVisible);
         return 0;
     }
@@ -450,6 +458,35 @@
         return 0;
     }
 
+    private int runIsVisibleBackgroundUserSupported() {
+        PrintWriter pw = getOutPrintWriter();
+
+        boolean verbose = false;
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            switch (opt) {
+                case "-v":
+                case "--verbose":
+                    verbose = true;
+                    break;
+                default:
+                    pw.println("Invalid option: " + opt);
+                    return -1;
+            }
+        }
+
+        boolean effective = UserManager.isVisibleBackgroundUsersEnabled();
+        if (!verbose) {
+            // NOTE: do not change output below, as it's used by ITestDevice
+            // (it's ok to change the verbose option though)
+            pw.println(effective);
+        } else {
+            pw.printf("effective=%b real=%b\n", effective, Resources.getSystem()
+                    .getBoolean(R.bool.config_multiuserVisibleBackgroundUsers));
+        }
+        return 0;
+    }
+
     private int runIsVisibleBackgroundUserOnDefaultDisplaySupported() {
         PrintWriter pw = getOutPrintWriter();
 
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index e9dc082..37ed4ac 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -69,6 +69,7 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
+import android.os.IProgressListener;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Process;
@@ -848,7 +849,8 @@
         mInjector.secondaryDisplayIdsForStartingBackgroundUsers = new int[]{4, 8, 15, 16, 23, 42};
 
         assertThrows(IllegalArgumentException.class,
-                () -> mAms.startUserInBackgroundVisibleOnDisplay(USER_ID, 666));
+                () -> mAms.startUserInBackgroundVisibleOnDisplay(USER_ID, 666,
+                        /* unlockProgressListener= */ null));
 
         assertWithMessage("UserController.startUserOnSecondaryDisplay() calls")
                 .that(mInjector.usersStartedOnSecondaryDisplays).isEmpty();
@@ -859,7 +861,8 @@
         mInjector.secondaryDisplayIdsForStartingBackgroundUsers = new int[]{ 4, 8, 15, 16, 23, 42 };
         mInjector.returnValueForstartUserOnSecondaryDisplay = false;
 
-        boolean started = mAms.startUserInBackgroundVisibleOnDisplay(USER_ID, 42);
+        boolean started = mAms.startUserInBackgroundVisibleOnDisplay(USER_ID, 42,
+                /* unlockProgressListener= */ null);
         Log.v(TAG, "Started: " + started);
 
         assertWithMessage("mAms.startUserInBackgroundOnDisplay(%s, 42)", USER_ID)
@@ -874,7 +877,8 @@
         mInjector.secondaryDisplayIdsForStartingBackgroundUsers = new int[]{ 4, 8, 15, 16, 23, 42 };
         mInjector.returnValueForstartUserOnSecondaryDisplay = true;
 
-        boolean started = mAms.startUserInBackgroundVisibleOnDisplay(USER_ID, 42);
+        boolean started = mAms.startUserInBackgroundVisibleOnDisplay(USER_ID, 42,
+                /* unlockProgressListener= */ null);
         Log.v(TAG, "Started: " + started);
 
         assertWithMessage("mAms.startUserInBackgroundOnDisplay(%s, 42)", USER_ID)
@@ -1009,7 +1013,8 @@
         }
 
         @Override
-        public boolean startUserInBackgroundVisibleOnDisplay(int userId, int displayId) {
+        public boolean startUserInBackgroundVisibleOnDisplay(int userId, int displayId,
+                IProgressListener unlockProgressListener) {
             usersStartedOnSecondaryDisplays.add(new Pair<>(userId, displayId));
             return returnValueForstartUserOnSecondaryDisplay;
         }
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index b146c27..e969268 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -244,7 +244,8 @@
 
     @Test
     public void testStartUserVisibleOnDisplay() {
-        boolean started = mUserController.startUserVisibleOnDisplay(TEST_USER_ID, 42);
+        boolean started = mUserController.startUserVisibleOnDisplay(TEST_USER_ID, 42,
+                /* unlockProgressListener= */ null);
 
         assertWithMessage("startUserOnDisplay(%s, %s)", TEST_USER_ID, 42).that(started).isTrue();
         verifyUserAssignedToDisplay(TEST_USER_ID, 42);