Merge "Override process config for cold start on secondary screens" into qt-dev
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 1344727..66b305e 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1085,6 +1085,22 @@
         if (root == this) {
             task.setRootProcess(proc);
         }
+        // Override the process configuration to match the display where the first activity in
+        // the process was launched. This can help with compat issues on secondary displays when
+        // apps use Application to obtain configuration or metrics instead of Activity.
+        final ActivityDisplay display = getDisplay();
+        if (display == null || display.mDisplayId == INVALID_DISPLAY) {
+            return;
+        }
+        if (!proc.hasActivities() && display.mDisplayId != DEFAULT_DISPLAY) {
+            proc.registerDisplayConfigurationListenerLocked(display);
+        } else if (display.mDisplayId == DEFAULT_DISPLAY) {
+            // Once an activity is launched on default display - stop listening for other displays
+            // configurations to maintain compatibility with previous platform releases. E.g. when
+            // an activity is launched in a Bubble and then moved to default screen, we should match
+            // the global device config.
+            proc.unregisterDisplayConfigurationListenerLocked();
+        }
     }
 
     boolean hasProcess() {
@@ -3233,7 +3249,7 @@
         // Update last reported values.
         final Configuration newMergedOverrideConfig = getMergedOverrideConfiguration();
 
-        setLastReportedConfiguration(mAtmService.getGlobalConfiguration(), newMergedOverrideConfig);
+        setLastReportedConfiguration(getProcessGlobalConfiguration(), newMergedOverrideConfig);
 
         if (mState == INITIALIZING) {
             // No need to relaunch or schedule new config for activity that hasn't been launched
@@ -3342,6 +3358,14 @@
         return true;
     }
 
+    /** Get process configuration, or global config if the process is not set. */
+    private Configuration getProcessGlobalConfiguration() {
+        if (app != null) {
+            return app.getConfiguration();
+        }
+        return mAtmService.getGlobalConfiguration();
+    }
+
     /**
      * When assessing a configuration change, decide if the changes flags and the new configurations
      * should cause the Activity to relaunch.
@@ -3449,7 +3473,7 @@
             mStackSupervisor.activityRelaunchingLocked(this);
             final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(pendingResults,
                     pendingNewIntents, configChangeFlags,
-                    new MergedConfiguration(mAtmService.getGlobalConfiguration(),
+                    new MergedConfiguration(getProcessGlobalConfiguration(),
                             getMergedOverrideConfiguration()),
                     preserveWindow);
             final ActivityLifecycleItem lifecycleItem;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 11a177a..f8fd64a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Surface.ROTATION_0;
 import static android.view.Surface.ROTATION_90;
@@ -38,6 +40,7 @@
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE;
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -56,10 +59,10 @@
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
-import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
 import android.util.MergedConfiguration;
 import android.util.MutableBoolean;
+import android.view.DisplayInfo;
 import android.view.IRemoteAnimationFinishedCallback;
 import android.view.IRemoteAnimationRunner.Stub;
 import android.view.RemoteAnimationAdapter;
@@ -598,6 +601,67 @@
         assertNull(mActivity.pendingOptions);
     }
 
+    @Test
+    public void testSetProcessOverridesConfig() {
+        final ActivityRecord defaultDisplayActivity =
+                createActivityOnDisplay(true /* defaultDisplay */, null /* process */);
+        assertFalse(defaultDisplayActivity.app.registeredForDisplayConfigChanges());
+
+        final ActivityRecord secondaryDisplayActivity =
+                createActivityOnDisplay(false /* defaultDisplay */, null /* process */);
+        assertTrue(secondaryDisplayActivity.app.registeredForDisplayConfigChanges());
+        assertEquals(secondaryDisplayActivity.getDisplay().getResolvedOverrideConfiguration(),
+                secondaryDisplayActivity.app.getRequestedOverrideConfiguration());
+
+        assertNotEquals(defaultDisplayActivity.getConfiguration(),
+                secondaryDisplayActivity.getConfiguration());
+    }
+
+    @Test
+    public void testSetProcessDoesntOverrideConfigIfAnotherActivityPresent() {
+        final ActivityRecord defaultDisplayActivity =
+                createActivityOnDisplay(true /* defaultDisplay */, null /* process */);
+        assertFalse(defaultDisplayActivity.app.registeredForDisplayConfigChanges());
+
+        final ActivityRecord secondaryDisplayActivity =
+                createActivityOnDisplay(false /* defaultDisplay */, defaultDisplayActivity.app);
+        assertFalse(secondaryDisplayActivity.app.registeredForDisplayConfigChanges());
+    }
+
+    @Test
+    public void testActivityOnDefaultDisplayClearsProcessOverride() {
+        final ActivityRecord secondaryDisplayActivity =
+                createActivityOnDisplay(false /* defaultDisplay */, null /* process */);
+        assertTrue(secondaryDisplayActivity.app.registeredForDisplayConfigChanges());
+
+        final ActivityRecord defaultDisplayActivity =
+                createActivityOnDisplay(true /* defaultDisplay */,
+                        secondaryDisplayActivity.app);
+        assertFalse(defaultDisplayActivity.app.registeredForDisplayConfigChanges());
+        assertFalse(secondaryDisplayActivity.app.registeredForDisplayConfigChanges());
+    }
+
+    /**
+     * Creates an activity on display. For non-default display request it will also create a new
+     * display with custom DisplayInfo.
+     */
+    private ActivityRecord createActivityOnDisplay(boolean defaultDisplay,
+            WindowProcessController process) {
+        final ActivityDisplay display;
+        if (defaultDisplay) {
+            display = mRootActivityContainer.getDefaultDisplay();
+        } else {
+            final DisplayInfo info = new DisplayInfo();
+            info.logicalWidth = 100;
+            info.logicalHeight = 100;
+            display = addNewActivityDisplayAt(info, POSITION_TOP);
+        }
+        final TestActivityStack stack = display.createStack(WINDOWING_MODE_UNDEFINED,
+                ACTIVITY_TYPE_STANDARD, true /* onTop */);
+        final TaskRecord task = new TaskBuilder(mSupervisor).setStack(stack).build();
+        return new ActivityBuilder(mService).setTask(task).setUseProcess(process).build();
+    }
+
     /** Setup {@link #mActivity} as a size-compat-mode-able activity without fixed orientation. */
     private void prepareFixedAspectRatioUnresizableActivity() {
         setupDisplayContentForCompatDisplayInsets();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 53b0add..d8c0de7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -195,6 +195,7 @@
         private ActivityStack mStack;
         private int mActivityFlags;
         private int mLaunchMode;
+        private WindowProcessController mWpc;
 
         ActivityBuilder(ActivityTaskManagerService service) {
             mService = service;
@@ -245,6 +246,11 @@
             return this;
         }
 
+        ActivityBuilder setUseProcess(WindowProcessController wpc) {
+            mWpc = wpc;
+            return this;
+        }
+
         ActivityRecord build() {
             if (mComponent == null) {
                 final int id = sCurrentActivityId++;
@@ -290,12 +296,18 @@
                 mTaskRecord.addActivityToTop(activity);
             }
 
-            final WindowProcessController wpc = new WindowProcessController(mService,
-                    mService.mContext.getApplicationInfo(), "name", 12345,
-                    UserHandle.getUserId(12345), mock(Object.class),
-                    mock(WindowProcessListener.class));
-            wpc.setThread(mock(IApplicationThread.class));
+            final WindowProcessController wpc;
+            if (mWpc != null) {
+                wpc = mWpc;
+            } else {
+                wpc = new WindowProcessController(mService,
+                        mService.mContext.getApplicationInfo(), "name", 12345,
+                        UserHandle.getUserId(12345), mock(Object.class),
+                        mock(WindowProcessListener.class));
+                wpc.setThread(mock(IApplicationThread.class));
+            }
             activity.setProcess(wpc);
+            wpc.addActivityIfNeeded(activity);
             return activity;
         }
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 7f35dac..8528954 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -153,7 +153,6 @@
     @FlakyTest(bugId = 131005232)
     public void testLandscapeSeascapeRotationByApp() {
         // Some plumbing to get the service ready for rotation updates.
-        mWm.mDisplayReady = true;
         mWm.mDisplayEnabled = true;
 
         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
@@ -186,7 +185,6 @@
     @Test
     public void testLandscapeSeascapeRotationByPolicy() {
         // Some plumbing to get the service ready for rotation updates.
-        mWm.mDisplayReady = true;
         mWm.mDisplayEnabled = true;
 
         final DisplayRotation spiedRotation = spy(mDisplayContent.getDisplayRotation());
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 366acea..427a929 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -41,6 +41,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.IntentFilter;
+import android.content.res.Configuration;
 import android.database.ContentObserver;
 import android.hardware.display.DisplayManagerInternal;
 import android.net.Uri;
@@ -175,6 +176,12 @@
         // Display creation is driven by the ActivityManagerService via
         // ActivityStackSupervisor. We emulate those steps here.
         mWindowManagerService.mRoot.createDisplayContent(display, mock(ActivityDisplay.class));
+        mWindowManagerService.displayReady();
+
+        final Configuration defaultDisplayConfig =
+                mWindowManagerService.computeNewConfiguration(DEFAULT_DISPLAY);
+        doReturn(defaultDisplayConfig).when(atms).getGlobalConfiguration();
+        doReturn(defaultDisplayConfig).when(atms).getGlobalConfigurationForPid(anyInt());
 
         mMockTracker.stopTracking();
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 3a702cb9..de28b5f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -154,7 +154,6 @@
             context.getDisplay().getDisplayInfo(mDisplayInfo);
             mDisplayContent = createNewDisplay();
             mWm.mDisplayEnabled = true;
-            mWm.mDisplayReady = true;
 
             // Set-up some common windows.
             mCommonWindows = new HashSet<>();