diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 19b13c1bcc6f0..bba645a70acf4 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -6372,7 +6372,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } final IBinder freezeToken = mayFreezeScreenLocked() ? appToken : null; - onDescendantOrientationChanged(freezeToken, this); + if (onDescendantOrientationChanged(freezeToken, this)) { + // The app is just becoming visible, and the parent Task has updated with the + // orientation request. Update the size compat mode. + updateSizeCompatMode(); + } } /** @@ -6538,6 +6542,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return; } + if (task == null || (!handlesOrientationChangeFromDescendant() + && task.getLastTaskBoundsComputeActivity() != this)) { + // Don't compute when Task hasn't computed its bounds for this app, because the Task can + // be letterboxed, and its bounds may not be accurate until then. + return; + } + Configuration overrideConfig = getRequestedOverrideConfiguration(); final Configuration fullConfig = getConfiguration(); @@ -6562,20 +6573,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mCompatDisplayInsets = new CompatDisplayInsets(mDisplayContent, this); } - void clearSizeCompatMode(boolean recomputeTask) { + @VisibleForTesting + void clearSizeCompatMode() { mSizeCompatScale = 1f; mSizeCompatBounds = null; mCompatDisplayInsets = null; - if (recomputeTask) { - // Recompute from Task because letterbox can also happen on Task level. - task.onRequestedOverrideConfigurationChanged(task.getRequestedOverrideConfiguration()); - } - } - - @VisibleForTesting - void clearSizeCompatMode() { - clearSizeCompatMode(true /* recomputeTask */); + // Recompute from Task because letterbox can also happen on Task level. + task.onRequestedOverrideConfigurationChanged(task.getRequestedOverrideConfiguration()); } @Override diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index cbb3c4255d281..0b2ba8727abe5 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -571,6 +571,10 @@ class Task extends WindowContainer { /** Current activity that is resumed, or null if there is none. */ ActivityRecord mResumedActivity = null; + /** Last activity that is used to compute the Task bounds. */ + @Nullable + private ActivityRecord mLastTaskBoundsComputeActivity; + private boolean mForceShowForAllUsers; /** When set, will force the task to report as invisible. */ @@ -1496,6 +1500,11 @@ class Task extends WindowContainer { } void cleanUpActivityReferences(ActivityRecord r) { + // mLastTaskBoundsComputeActivity is set at leaf Task + if (mLastTaskBoundsComputeActivity == r) { + mLastTaskBoundsComputeActivity = null; + } + final WindowContainer parent = getParent(); if (parent != null && parent.asTask() != null) { parent.asTask().cleanUpActivityReferences(r); @@ -2833,6 +2842,8 @@ class Task extends WindowContainer { private void resolveLeafOnlyOverrideConfigs(Configuration newParentConfig, Rect previousBounds) { + mLastTaskBoundsComputeActivity = getTopNonFinishingActivity(false /* includeOverlays */); + int windowingMode = getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode(); if (windowingMode == WINDOWING_MODE_UNDEFINED) { @@ -2963,6 +2974,11 @@ class Task extends WindowContainer { return bounds; } + @Nullable + ActivityRecord getLastTaskBoundsComputeActivity() { + return mLastTaskBoundsComputeActivity; + } + /** Updates the task's bounds and override configuration to match what is expected for the * input stack. */ void updateOverrideConfigurationForStack(Task inStack) { @@ -3307,18 +3323,6 @@ class Task extends WindowContainer { // No one in higher hierarchy handles this request, let's adjust our bounds to fulfill // it if possible. if (getParent() != null) { - final ActivityRecord activity = requestingContainer.asActivityRecord(); - if (activity != null) { - // Clear the size compat cache to recompute the bounds for requested orientation; - // otherwise when Task#computeFullscreenBounds(), it will not try to do Task level - // letterboxing because app may prefer to keep its original size (size compat). - // - // Normally, ActivityRecord#clearSizeCompatMode() recomputes from its parent Task, - // which is the leaf Task. However, because this orientation request is new to all - // Tasks, pass false to clearSizeCompatMode, and trigger onConfigurationChanged from - // here (root Task) to make sure all Tasks are up-to-date. - activity.clearSizeCompatMode(false /* recomputeTask */); - } onConfigurationChanged(getParent().getConfiguration()); return true; } diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index 4300971be6897..ddc29f5dd516a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -41,6 +41,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.same; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doCallRealMethod; import android.app.ActivityManager; @@ -702,7 +703,6 @@ public class SizeCompatTests extends WindowTestsBase { // size compat cache. verify(mTask).onDescendantOrientationChanged(any(), same(newActivity)); verify(mTask).computeFullscreenBounds(any(), any(), any(), anyInt()); - verify(newActivity).clearSizeCompatMode(false /* recomputeTask */); final Rect displayBounds = display.getBounds(); final Rect taskBounds = mTask.getBounds(); @@ -744,7 +744,6 @@ public class SizeCompatTests extends WindowTestsBase { // size compat cache. verify(mTask).onDescendantOrientationChanged(any(), same(newActivity)); verify(mTask).computeFullscreenBounds(any(), any(), any(), anyInt()); - verify(newActivity).clearSizeCompatMode(false /* recomputeTask */); final Rect displayBounds = display.getBounds(); final Rect taskBounds = mTask.getBounds(); @@ -761,6 +760,40 @@ public class SizeCompatTests extends WindowTestsBase { assertEquals(taskBounds, newActivityBounds); } + @Test + public void testDisplayIgnoreOrientationRequest_pausedAppNotLostSizeCompat() { + // Set up a display in landscape and ignoring orientation request. + setUpDisplaySizeWithApp(2800, 1400); + final DisplayContent display = mActivity.mDisplayContent; + display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + + // Portrait fixed app. + prepareUnresizable(0, SCREEN_ORIENTATION_PORTRAIT); + clearInvocations(mActivity); + + assertTrue(mTask.isTaskLetterboxed()); + assertFalse(mActivity.inSizeCompatMode()); + assertEquals(mTask.getLastTaskBoundsComputeActivity(), mActivity); + + // Rotate display to portrait. + rotateDisplay(mActivity.mDisplayContent, ROTATION_90); + + // App should be in size compat. + assertFalse(mTask.isTaskLetterboxed()); + assertScaled(); + assertEquals(mTask.getLastTaskBoundsComputeActivity(), mActivity); + + final Rect activityBounds = new Rect(mActivity.getBounds()); + mStack.resumeTopActivityUncheckedLocked(null /* prev */, null /* options */); + + // App still in size compat, and the bounds don't change. + verify(mActivity, never()).clearSizeCompatMode(); + assertFalse(mTask.isTaskLetterboxed()); + assertScaled(); + assertEquals(mTask.getLastTaskBoundsComputeActivity(), mActivity); + assertEquals(activityBounds, mActivity.getBounds()); + } + private static WindowState addWindowToActivity(ActivityRecord activity) { final WindowManager.LayoutParams params = new WindowManager.LayoutParams(); params.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java index 0b257ee876200..238f31448ba1d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java @@ -257,4 +257,24 @@ public class TaskTests extends WindowTestsBase { task.resolveOverrideConfiguration(parentConfig); assertThat(resolvedOverride.getWindowingMode()).isEqualTo(WINDOWING_MODE_UNDEFINED); } + + @Test + public void testCleanUpActivityReferences_clearLastTaskBoundsComputeActivity() { + final Task rootTask = createTaskStackOnDisplay(mDisplayContent); + final Task leafTask = createTaskInStack(rootTask, 0 /* userId */); + final ActivityRecord activity2 = createActivityRecord(mDisplayContent, leafTask); + final ActivityRecord activity1 = createActivityRecord(mDisplayContent, leafTask); + activity1.finishing = false; + leafTask.resolveOverrideConfiguration(rootTask.getConfiguration()); + + assertEquals(activity1, leafTask.getLastTaskBoundsComputeActivity()); + + leafTask.cleanUpActivityReferences(activity2); + + assertNotNull(leafTask.getLastTaskBoundsComputeActivity()); + + leafTask.cleanUpActivityReferences(activity1); + + assertNull(leafTask.getLastTaskBoundsComputeActivity()); + } }