Ignore stopped state when becoming visible and ensuring configuration.

We normally don't ensure configuration for activities in the stopped
state since it doesn't make sense to be relaunching something that isn't
visible. However, if the activity is becoming visible, then ignore the
stopped state allowing the configuration to be ensured and the activity
relaunched if needed.

Change-Id: If953b624105c8c522f01cfb8fc68ded4fb18698d
Fixes: 73696401
Test: atest ActivityLifecycleTests#testRelaunchConfigurationChangedWhileBecomingVisible
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6fcdc3e..d4307d7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -22355,7 +22355,7 @@
         // Update the configuration with WM first and check if any of the stacks need to be resized
         // due to the configuration change. If so, resize the stacks now and do any relaunches if
         // necessary. This way we don't need to relaunch again afterwards in
-        // ensureActivityConfigurationLocked().
+        // ensureActivityConfiguration().
         if (mWindowManager != null) {
             final int[] resizedStacks =
                     mWindowManager.setNewDisplayOverrideConfiguration(mTempConfig, displayId);
@@ -22383,7 +22383,7 @@
             }
 
             if (starting != null) {
-                kept = starting.ensureActivityConfigurationLocked(changes,
+                kept = starting.ensureActivityConfiguration(changes,
                         false /* preserveWindow */);
                 // And we need to make sure at this point that all other activities
                 // are made visible with the correct configuration.
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 06faeb9..8cc9273 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -361,7 +361,7 @@
     private boolean mTurnScreenOn;
 
     /**
-     * Temp configs used in {@link #ensureActivityConfigurationLocked(int, boolean)}
+     * Temp configs used in {@link #ensureActivityConfiguration(int, boolean)}
      */
     private final Configuration mTmpConfig = new Configuration();
     private final Rect mTmpBounds = new Rect();
@@ -2365,13 +2365,27 @@
         outBounds.offsetTo(left, 0 /* top */);
     }
 
+    boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow) {
+        return ensureActivityConfiguration(globalChanges, preserveWindow,
+                false /* ignoreStopState */);
+    }
+
     /**
-     * Make sure the given activity matches the current configuration. Returns false if the activity
-     * had to be destroyed.  Returns true if the configuration is the same, or the activity will
-     * remain running as-is for whatever reason. Ensures the HistoryRecord is updated with the
-     * correct configuration and all other bookkeeping is handled.
+     * Make sure the given activity matches the current configuration. Ensures the HistoryRecord
+     * is updated with the correct configuration and all other bookkeeping is handled.
+     *
+     * @param globalChanges The changes to the global configuration.
+     * @param preserveWindow If the activity window should be preserved on screen if the activity
+     *                       is relaunched.
+     * @param ignoreStopState If we should try to relaunch the activity even if it is in the stopped
+     *                        state. This is useful for the case where we know the activity will be
+     *                        visible soon and we want to ensure its configuration before we make it
+     *                        visible.
+     * @return True if the activity was relaunched and false if it wasn't relaunched because we
+     *         can't or the app handles the specific configuration that is changing.
      */
-    boolean ensureActivityConfigurationLocked(int globalChanges, boolean preserveWindow) {
+    boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow,
+            boolean ignoreStopState) {
         final ActivityStack stack = getStack();
         if (stack.mConfigWillChange) {
             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
@@ -2387,8 +2401,7 @@
             return true;
         }
 
-        // Skip updating configuration for activity that are stopping or stopped.
-        if (mState == STOPPING || mState == STOPPED) {
+        if (!ignoreStopState && (mState == STOPPING || mState == STOPPED)) {
             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
                     "Skipping config check stopped or stopping: " + this);
             return true;
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 817b699..4987b33 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -123,7 +123,6 @@
 import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Binder;
-import android.os.Bundle;
 import android.os.Debug;
 import android.os.Handler;
 import android.os.IBinder;
@@ -1851,7 +1850,10 @@
                         // First: if this is not the current activity being started, make
                         // sure it matches the current configuration.
                         if (r != starting) {
-                            r.ensureActivityConfigurationLocked(0 /* globalChanges */, preserveWindows);
+                            // Ensure activity configuration ignoring stop state since we are
+                            // becoming visible.
+                            r.ensureActivityConfiguration(0 /* globalChanges */, preserveWindows,
+                                    true /* ignoreStopState */);
                         }
 
                         if (r.app == null || r.app.thread == null) {
@@ -4627,7 +4629,7 @@
                     (start.getTask() == task) ? activities.indexOf(start) : activities.size() - 1;
             for (; activityIndex >= 0; --activityIndex) {
                 final ActivityRecord r = activities.get(activityIndex);
-                updatedConfig |= r.ensureActivityConfigurationLocked(0 /* globalChanges */,
+                updatedConfig |= r.ensureActivityConfiguration(0 /* globalChanges */,
                         preserveWindow);
                 if (r.fullscreen) {
                     behindFullscreen = true;
diff --git a/services/core/java/com/android/server/am/CompatModePackages.java b/services/core/java/com/android/server/am/CompatModePackages.java
index d84f487..c6947ab 100644
--- a/services/core/java/com/android/server/am/CompatModePackages.java
+++ b/services/core/java/com/android/server/am/CompatModePackages.java
@@ -369,7 +369,7 @@
             }
 
             if (starting != null) {
-                starting.ensureActivityConfigurationLocked(0 /* globalChanges */,
+                starting.ensureActivityConfiguration(0 /* globalChanges */,
                         false /* preserveWindow */);
                 // And we need to make sure at this point that all other activities
                 // are made visible with the correct configuration.
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index a07afde..6f6e0d9 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -537,7 +537,7 @@
             if (updatedConfig) {
                 final ActivityRecord r = topRunningActivityLocked();
                 if (r != null && !deferResume) {
-                    kept = r.ensureActivityConfigurationLocked(0 /* globalChanges */,
+                    kept = r.ensureActivityConfiguration(0 /* globalChanges */,
                             preserveWindow);
                     mService.mStackSupervisor.ensureActivitiesVisibleLocked(r, 0,
                             !PRESERVE_WINDOWS);
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
index 5161114..8b21059 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
@@ -161,7 +161,7 @@
         when(mService.mWindowManager.getNavBarPosition()).thenReturn(navBarPosition);
         mTask.getConfiguration().windowConfiguration.setAppBounds(taskBounds);
         mActivity.info.maxAspectRatio = aspectRatio;
-        mActivity.ensureActivityConfigurationLocked(
+        mActivity.ensureActivityConfiguration(
                 0 /* globalChanges */, false /* preserveWindow */);
         assertEquals(expectedActivityBounds, mActivity.getBounds());
     }