From 3e4f8e1a7c731a03a587bcf2b478aa40caab2356 Mon Sep 17 00:00:00 2001 From: Chris Li Date: Fri, 15 Jan 2021 21:47:15 -0800 Subject: [PATCH] Task letterbox for resizable fixed-orientation app in dual DisplayAreas Before, when both DisplayAreaGroups set ignoreOrientationRequest to false, launching two resizable apps with different orientations will end up with two apps in the same orientations. One app is in the orientation different from its request. This is because Task only letterboxes when ignoreOrientationRequest is true, but it should also letterbox when the TaskDisplayArea can't specify orientation (happens when it doesn't have focus). Bug: 176566401 Test: atest WmTests:DualDisplayAreaGroupPolicyTest Change-Id: I6f093f3c2631970fcc2fa839e5b394106e5acc29 --- .../core/java/com/android/server/wm/Task.java | 8 ++++ .../android/server/wm/TaskDisplayArea.java | 1 - .../wm/DualDisplayAreaGroupPolicyTest.java | 38 +++++++++++++++++++ .../android/server/wm/SizeCompatTests.java | 29 ++++++++++---- 4 files changed, 67 insertions(+), 9 deletions(-) diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 042b7e36428b9..855c8f562dda4 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -3329,6 +3329,14 @@ class Task extends WindowContainer { return false; } + @Override + boolean handlesOrientationChangeFromDescendant() { + return super.handlesOrientationChangeFromDescendant() + // Display won't rotate for the orientation request if the TaskDisplayArea can't + // specify orientation. + && getDisplayArea().canSpecifyOrientation(); + } + void resize(boolean relayout, boolean forced) { if (setBounds(getRequestedOverrideBounds(), forced) != BOUNDS_CHANGE_NONE && relayout) { getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index bc0235c0e934f..0136c010429b8 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -1902,7 +1902,6 @@ final class TaskDisplayArea extends DisplayArea { } /** Whether this task display area can request orientation. */ - @VisibleForTesting boolean canSpecifyOrientation() { // Only allow to specify orientation if this TDA is not set to ignore orientation request, // and it is the last focused one on this logical display that can request orientation diff --git a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java index 61911b3c36beb..e6f24da3e7b93 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java @@ -33,6 +33,7 @@ import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST; import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.server.wm.SizeCompatTests.prepareLimitedBounds; import static com.android.server.wm.SizeCompatTests.prepareUnresizable; import static com.android.server.wm.SizeCompatTests.rotateDisplay; @@ -309,6 +310,43 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase { assertThat(mSecondRoot.findAreaForToken(imeToken)).isEqualTo(imeContainer); } + @Test + public void testResizableFixedOrientationApp_taskLevelLetterboxing() { + mFirstRoot.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */); + mSecondRoot.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */); + + // Launch portrait on first DAG + mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda); + prepareLimitedBounds(mFirstActivity, SCREEN_ORIENTATION_PORTRAIT, + false /* isUnresizable */); + + // Display in landscape (as opposite to DAG), first DAG and activity in portrait + assertThat(mDisplay.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE); + assertThat(mFirstRoot.getConfiguration().orientation).isEqualTo(ORIENTATION_PORTRAIT); + assertThat(mFirstActivity.getConfiguration().orientation).isEqualTo(ORIENTATION_PORTRAIT); + assertThat(mFirstTask.isTaskLetterboxed()).isFalse(); + assertThat(mFirstActivity.inSizeCompatMode()).isFalse(); + + // Launch portrait on second DAG + mDisplay.onLastFocusedTaskDisplayAreaChanged(mSecondTda); + prepareLimitedBounds(mSecondActivity, SCREEN_ORIENTATION_LANDSCAPE, + false /* isUnresizable */); + + // Display in portrait (as opposite to DAG), first DAG and activity in landscape + assertThat(mDisplay.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_PORTRAIT); + assertThat(mSecondRoot.getConfiguration().orientation).isEqualTo(ORIENTATION_LANDSCAPE); + assertThat(mSecondActivity.getConfiguration().orientation).isEqualTo(ORIENTATION_LANDSCAPE); + assertThat(mSecondTask.isTaskLetterboxed()).isFalse(); + assertThat(mSecondActivity.inSizeCompatMode()).isFalse(); + + // First activity is letterboxed in portrait as requested. + assertThat(mFirstRoot.getConfiguration().orientation).isEqualTo(ORIENTATION_LANDSCAPE); + assertThat(mFirstActivity.getConfiguration().orientation).isEqualTo(ORIENTATION_PORTRAIT); + assertThat(mFirstTask.isTaskLetterboxed()).isTrue(); + assertThat(mFirstActivity.inSizeCompatMode()).isFalse(); + + } + private void setupImeWindow() { final WindowState imeWindow = createWindow(null /* parent */, TYPE_INPUT_METHOD, mDisplay, "mImeWindow"); 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 22430a110ca3e..eb44476a86184 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; @@ -505,7 +506,7 @@ public class SizeCompatTests extends WindowTestsBase { compatTokens.clear(); // Make the activity resizable again by restarting it - activity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE; + activity.info.resizeMode = RESIZE_MODE_RESIZEABLE; activity.mVisibleRequested = true; activity.restartProcessIfVisible(); // The full lifecycle isn't hooked up so manually set state to resumed @@ -522,7 +523,7 @@ public class SizeCompatTests extends WindowTestsBase { setUpDisplaySizeWithApp(1000, 2500); // Make the task root resizable. - mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE; + mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; // Create a size compat activity on the same task. final ActivityRecord activity = new ActivityBuilder(mAtm) @@ -550,7 +551,7 @@ public class SizeCompatTests extends WindowTestsBase { setUpDisplaySizeWithApp(1000, 2500); // Make the task root resizable. - mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE; + mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; // Create a size compat activity on the same task. final ActivityRecord activity = new ActivityBuilder(mAtm) @@ -946,13 +947,25 @@ public class SizeCompatTests extends WindowTestsBase { prepareUnresizable(activity, -1 /* maxAspect */, screenOrientation); } - /** - * Setups {@link #mActivity} as a size-compat-mode-able activity with fixed aspect and/or - * orientation. - */ static void prepareUnresizable(ActivityRecord activity, float maxAspect, int screenOrientation) { - activity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE; + prepareLimitedBounds(activity, maxAspect, screenOrientation, true /* isUnresizable */); + } + + static void prepareLimitedBounds(ActivityRecord activity, int screenOrientation, + boolean isUnresizable) { + prepareLimitedBounds(activity, -1 /* maxAspect */, screenOrientation, isUnresizable); + } + + /** + * Setups {@link #mActivity} with restriction on its bounds, such as maxAspect, fixed + * orientation, and/or whether it is resizable. + */ + static void prepareLimitedBounds(ActivityRecord activity, float maxAspect, + int screenOrientation, boolean isUnresizable) { + activity.info.resizeMode = isUnresizable + ? RESIZE_MODE_UNRESIZEABLE + : RESIZE_MODE_RESIZEABLE; activity.mVisibleRequested = true; if (maxAspect >= 0) { activity.info.maxAspectRatio = maxAspect;