diff options
5 files changed, 118 insertions, 10 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index b40154e8db0c..d9faaf868b3a 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -6543,14 +6543,20 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mCompatDisplayInsets = new CompatDisplayInsets(mDisplayContent, this); } - @VisibleForTesting - void clearSizeCompatMode() { + void clearSizeCompatMode(boolean recomputeTask) { mSizeCompatScale = 1f; mSizeCompatBounds = null; mCompatDisplayInsets = null; - // Recompute from Task because letterbox can also happen on Task level. - task.onRequestedOverrideConfigurationChanged(task.getRequestedOverrideConfiguration()); + if (recomputeTask) { + // Recompute from Task because letterbox can also happen on Task level. + task.onRequestedOverrideConfigurationChanged(task.getRequestedOverrideConfiguration()); + } + } + + @VisibleForTesting + void clearSizeCompatMode() { + clearSizeCompatMode(true /* recomputeTask */); } @Override diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 98a1bacf27e0..e8a4dc3814d0 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -1303,7 +1303,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp @Override boolean onDescendantOrientationChanged(IBinder freezeDisplayToken, - ConfigurationContainer requestingContainer) { + WindowContainer requestingContainer) { final Configuration config = updateOrientation( getRequestedOverrideConfiguration(), freezeDisplayToken, false /* forceUpdate */); // If display rotation class tells us that it doesn't consider app requested orientation, diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 4b12fe1c5e38..d423766e9430 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -3274,7 +3274,7 @@ class Task extends WindowContainer<WindowContainer> { @Override public boolean onDescendantOrientationChanged(IBinder freezeDisplayToken, - ConfigurationContainer requestingContainer) { + WindowContainer requestingContainer) { if (super.onDescendantOrientationChanged(freezeDisplayToken, requestingContainer)) { return true; } @@ -3282,6 +3282,18 @@ class Task extends WindowContainer<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/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index da3a92856fe5..cec2b7335554 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -1144,7 +1144,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< * @return {@code true} if handled; {@code false} otherwise. */ boolean onDescendantOrientationChanged(@Nullable IBinder freezeDisplayToken, - @Nullable ConfigurationContainer requestingContainer) { + @Nullable WindowContainer requestingContainer) { final WindowContainer parent = getParent(); if (parent == null) { return false; @@ -1156,7 +1156,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< /** * Check if this container or its parent will handle orientation changes from descendants. It's * different from the return value of {@link #onDescendantOrientationChanged(IBinder, - * ConfigurationContainer)} in the sense that the return value of this method tells if this + * WindowContainer)} in the sense that the return value of this method tells if this * container or its parent will handle the request eventually, while the return value of the * other method is if it handled the request synchronously. * @@ -1230,7 +1230,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< * to ensure it gets correct configuration. */ void setOrientation(int orientation, @Nullable IBinder freezeDisplayToken, - @Nullable ConfigurationContainer requestingContainer) { + @Nullable WindowContainer requestingContainer) { if (mOrientation == orientation) { return; } 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 7a1b17dfead7..b7f6564b4135 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -28,6 +28,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.Task.ActivityState.STOPPED; @@ -35,8 +36,11 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; 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.doCallRealMethod; import android.app.ActivityManager; @@ -628,7 +632,6 @@ public class SizeCompatTests extends WindowTestsBase { rotateDisplay(mActivity.mDisplayContent, ROTATION_90); final Rect displayBounds = mActivity.mDisplayContent.getBounds(); - final Rect newTaskBounds = mTask.getBounds(); final Rect newActivityBounds = mActivity.getBounds(); assertTrue(displayBounds.width() < displayBounds.height()); @@ -673,6 +676,93 @@ public class SizeCompatTests extends WindowTestsBase { activityBounds.width()); } + @Test + public void testDisplayIgnoreOrientationRequest_newLaunchedOrientationAppInTaskLetterbox() { + // 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 without max aspect. + prepareUnresizable(0, SCREEN_ORIENTATION_PORTRAIT); + + assertTrue(mTask.isTaskLetterboxed()); + assertFalse(mActivity.inSizeCompatMode()); + + // Launch another portrait fixed app. + spyOn(mTask); + setBooted(display.mWmService.mAtmService); + final ActivityRecord newActivity = new ActivityBuilder(display.mWmService.mAtmService) + .setResizeMode(RESIZE_MODE_UNRESIZEABLE) + .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) + .setTask(mTask) + .build(); + + // Update with new activity requested orientation and recompute bounds with no previous + // 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(); + final Rect newActivityBounds = newActivity.getBounds(); + + // Task and app bounds should be 700x1400 with the ratio as the display. + assertTrue(mTask.isTaskLetterboxed()); + assertFalse(newActivity.inSizeCompatMode()); + assertEquals(taskBounds, newActivityBounds); + assertEquals(displayBounds.height(), taskBounds.height()); + assertEquals(displayBounds.height() * displayBounds.height() / displayBounds.width(), + taskBounds.width()); + } + + @Test + public void testDisplayIgnoreOrientationRequest_newLaunchedMaxAspectApp() { + // 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 without max aspect. + prepareUnresizable(0, SCREEN_ORIENTATION_PORTRAIT); + + assertTrue(mTask.isTaskLetterboxed()); + assertFalse(mActivity.inSizeCompatMode()); + + // Launch another portrait fixed app with max aspect ratio as 1.3. + spyOn(mTask); + setBooted(display.mWmService.mAtmService); + final ActivityRecord newActivity = new ActivityBuilder(display.mWmService.mAtmService) + .setResizeMode(RESIZE_MODE_UNRESIZEABLE) + .setMaxAspectRatio(1.3f) + .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) + .setTask(mTask) + .build(); + + // Update with new activity requested orientation and recompute bounds with no previous + // 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(); + final Rect newActivityBounds = newActivity.getBounds(); + + // Task bounds should be 700x1400 with the ratio as the display. + assertTrue(mTask.isTaskLetterboxed()); + assertEquals(displayBounds.height(), taskBounds.height()); + assertEquals(displayBounds.height() * displayBounds.height() / displayBounds.width(), + taskBounds.width()); + + // App bounds should be 700x(710 x 1.3 = 910) + assertFalse(newActivity.inSizeCompatMode()); + assertEquals(taskBounds.width(), newActivityBounds.width()); + assertEquals((long) Math.rint(taskBounds.width() * newActivity.info.maxAspectRatio), + newActivityBounds.height()); + } + private static WindowState addWindowToActivity(ActivityRecord activity) { final WindowManager.LayoutParams params = new WindowManager.LayoutParams(); params.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; |