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
This commit is contained in:
Chris Li
2021-01-15 21:47:15 -08:00
parent 81eb442457
commit 3e4f8e1a7c
4 changed files with 67 additions and 9 deletions

View File

@@ -3329,6 +3329,14 @@ class Task extends WindowContainer<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();

View File

@@ -1902,7 +1902,6 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
}
/** 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

View File

@@ -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");

View File

@@ -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;