Allow moving guest-to-guest user switching before going to sleep

- User switching after waking up can delay critical use cases.
- Allow running the switching before going into sleep : selectable from
  config_switchGuestUserBeforeGoingSleep overlay resource.
  Set to true by default.

- This change does not block entry into suspend so user switching taking time
  can continue after wake-up.

Bug: 151159894
Test: Switch into guest user and try sleep entry / wakeup.
Test: atest CarServiceUnitTest:com.android.car.CarPowerManagementServiceTest

Merged-In: I837d043a67ff69a0d02c15fbc1e4f0e62dcc37af
Change-Id: I837d043a67ff69a0d02c15fbc1e4f0e62dcc37af
(cherry picked from commit f2a3bb5a5ddfaefa11c9f438508297d171a5e24d)
diff --git a/service/res/values/config.xml b/service/res/values/config.xml
index afd8555..c55c7a6 100644
--- a/service/res/values/config.xml
+++ b/service/res/values/config.xml
@@ -254,4 +254,9 @@
     <!-- Controls the use of bluetooth voice recognition when long pressing the voice assist
          button. -->
     <bool name="enableLongPressBluetoothVoiceRecognition" translatable="false">true</bool>
+
+    <!-- Switch guest user into new guest user before going to sleep. If this is false, it will
+         be done after waking up from sleep. This only affects if the current user is a guest user.
+         -->
+    <bool name="config_switchGuestUserBeforeGoingSleep" translate="false">true</bool>
 </resources>
diff --git a/service/src/com/android/car/CarPowerManagementService.java b/service/src/com/android/car/CarPowerManagementService.java
index 222013c..340fd9b 100644
--- a/service/src/com/android/car/CarPowerManagementService.java
+++ b/service/src/com/android/car/CarPowerManagementService.java
@@ -132,6 +132,9 @@
     private static final String PROP_MAX_GARAGE_MODE_DURATION_OVERRIDE =
             "android.car.garagemodeduration";
 
+    // This is a temp work-around to reduce user switching delay after wake-up.
+    private final boolean mSwitchGuestUserBeforeSleep;
+
     private class PowerManagerCallbackList extends RemoteCallbackList<ICarPowerStateListener> {
         /**
          * Old version of {@link #onCallbackDied(E, Object)} that
@@ -163,6 +166,8 @@
                 .getBoolean(R.bool.config_disableUserSwitchDuringResume);
         sShutdownPrepareTimeMs = resources.getInteger(
                 R.integer.maxGarageModeRunningDurationInSecs) * 1000;
+        mSwitchGuestUserBeforeSleep = resources.getBoolean(
+                R.bool.config_switchGuestUserBeforeGoingSleep);
         if (sShutdownPrepareTimeMs < MIN_MAX_GARAGE_MODE_DURATION_MS) {
             Log.w(CarLog.TAG_POWER,
                     "maxGarageModeRunningDurationInSecs smaller than minimum required, resource:"
@@ -243,6 +248,7 @@
         writer.print(",mDisableUserSwitchDuringResume:" + mDisableUserSwitchDuringResume);
         writer.println(",mRebootAfterGarageMode:" + mRebootAfterGarageMode);
         writer.print("mNewGuestName: "); writer.println(mNewGuestName);
+        writer.println("mSwitchGuestUserBeforeSleep:" + mSwitchGuestUserBeforeSleep);
     }
 
     @Override
@@ -371,7 +377,9 @@
     private void handleOn() {
         // If current user is a Guest User, we want to inform CarUserNoticeService not to show
         // notice for current user, and show user notice only for the target user.
-        updateCarUserNoticeServiceIfNecessary();
+        if (!mSwitchGuestUserBeforeSleep) {
+            updateCarUserNoticeServiceIfNecessary();
+        }
 
         // Some OEMs have their own user-switching logic, which may not be coordinated with this
         // code. To avoid contention, we don't switch users when we coming alive. The OEM's code
@@ -406,6 +414,17 @@
         }
     }
 
+    private void switchUserIfCurrentUserIsGuest() {
+        int currentUserId = ActivityManager.getCurrentUser();
+        UserInfo currentUserInfo = mUserManager.getUserInfo(currentUserId);
+        boolean isGuest = currentUserInfo.isGuest();
+        if (!isGuest) {
+            return;
+        }
+        Log.d(CarLog.TAG_POWER, "Switching into new guest user before going to sleep");
+        doSwitchFromGuestToNewGuest(currentUserInfo);
+    }
+
     private void switchUserOnResumeIfNecessary(boolean allowSwitching) {
         int targetUserId = mCarUserManagerHelper.getInitialUser();
         if (targetUserId == UserHandle.USER_SYSTEM) {
@@ -457,20 +476,27 @@
         // At this point, target user is a guest - we cannot resume into an ephemeral guest for
         // privacy reasons, so we need to create a new guest and switch to it (even if the OEM
         // doesn't allow switching)
+        if (mSwitchGuestUserBeforeSleep) { // already handled
+            return;
+        }
 
+        doSwitchFromGuestToNewGuest(targetUserInfo);
+    }
 
-        boolean marked = mUserManager.markGuestForDeletion(targetUserId);
+    private void doSwitchFromGuestToNewGuest(UserInfo currentGuest) {
+        boolean marked = mUserManager.markGuestForDeletion(currentGuest.id);
         if (!marked) {
-            Log.w(CarLog.TAG_POWER, "Could not mark guest user " + targetUserId + " for deletion");
+            Log.w(CarLog.TAG_POWER,
+                    "Could not mark guest user " + currentGuest.id + " for deletion");
             return;
         }
 
         UserInfo newGuest = mUserManager.createGuest(mContext, mNewGuestName);
 
         if (newGuest != null) {
-            switchToUser(currentUserId, newGuest.id, "Created new guest");
-            Log.d(CarLog.TAG_POWER, "Removing previous guest " + targetUserId);
-            mUserManager.removeUser(targetUserId);
+            switchToUser(currentGuest.id, newGuest.id, "Created new guest");
+            Log.d(CarLog.TAG_POWER, "Removing previous guest " + currentGuest.id);
+            mUserManager.removeUser(currentGuest.id);
         } else {
             Log.wtf(CarLog.TAG_POWER, "Could not create new guest");
             // TODO(b/146380030): decide whether we should switch to SYSTEM
@@ -619,6 +645,9 @@
                     0 /*delay*/,
                     SHUTDOWN_POLLING_INTERVAL_MS);
         }
+        if (mSwitchGuestUserBeforeSleep) {
+            switchUserIfCurrentUserIsGuest();
+        }
     }
 
     private void sendPowerManagerEvent(int newState) {