Loading services/core/java/com/android/server/wm/ActivityRecord.java +10 −4 Original line number Diff line number Diff line Loading @@ -6552,15 +6552,21 @@ 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; if (recomputeTask) { // Recompute from Task because letterbox can also happen on Task level. task.onRequestedOverrideConfigurationChanged(task.getRequestedOverrideConfiguration()); } } @VisibleForTesting void clearSizeCompatMode() { clearSizeCompatMode(true /* recomputeTask */); } @Override public boolean matchParentBounds() { Loading services/core/java/com/android/server/wm/DisplayContent.java +1 −1 Original line number Diff line number Diff line Loading @@ -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, Loading services/core/java/com/android/server/wm/Task.java +13 −1 Original line number Diff line number Diff line Loading @@ -3283,7 +3283,7 @@ class Task extends WindowContainer<WindowContainer> { @Override public boolean onDescendantOrientationChanged(IBinder freezeDisplayToken, ConfigurationContainer requestingContainer) { WindowContainer requestingContainer) { if (super.onDescendantOrientationChanged(freezeDisplayToken, requestingContainer)) { return true; } Loading @@ -3291,6 +3291,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; } Loading services/core/java/com/android/server/wm/WindowContainer.java +3 −3 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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. * Loading Loading @@ -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; } Loading services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +91 −1 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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()); Loading Loading @@ -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; Loading Loading
services/core/java/com/android/server/wm/ActivityRecord.java +10 −4 Original line number Diff line number Diff line Loading @@ -6552,15 +6552,21 @@ 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; if (recomputeTask) { // Recompute from Task because letterbox can also happen on Task level. task.onRequestedOverrideConfigurationChanged(task.getRequestedOverrideConfiguration()); } } @VisibleForTesting void clearSizeCompatMode() { clearSizeCompatMode(true /* recomputeTask */); } @Override public boolean matchParentBounds() { Loading
services/core/java/com/android/server/wm/DisplayContent.java +1 −1 Original line number Diff line number Diff line Loading @@ -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, Loading
services/core/java/com/android/server/wm/Task.java +13 −1 Original line number Diff line number Diff line Loading @@ -3283,7 +3283,7 @@ class Task extends WindowContainer<WindowContainer> { @Override public boolean onDescendantOrientationChanged(IBinder freezeDisplayToken, ConfigurationContainer requestingContainer) { WindowContainer requestingContainer) { if (super.onDescendantOrientationChanged(freezeDisplayToken, requestingContainer)) { return true; } Loading @@ -3291,6 +3291,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; } Loading
services/core/java/com/android/server/wm/WindowContainer.java +3 −3 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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. * Loading Loading @@ -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; } Loading
services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +91 −1 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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()); Loading Loading @@ -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; Loading