From 4b038dd78f97a7e37e2db078da69a32ef1a469ca Mon Sep 17 00:00:00 2001 From: Massimo Carli Date: Wed, 23 Nov 2022 13:48:01 +0000 Subject: Respect "nosensor" and "locked" with ignoreOrientationRequest being set In this implementation, we always resolve the orientation for a component as the ignoreOrientationRequest was disabled. We then use the actual flag when deciding the display orientation and when querying from a descendent to handle the orientation change itself. Main use case why this is important is Camera apps that rely on those properties to ensure that they will be able to determine Camera preview orientation correctly Fixes:254691921 Test: run `atest WmTests:ActivityRecordTests WmTests:TaskTests WmTests:WindowContainerTests` Change-Id: I96dca18a561e2acf961a462d3a4db484f003be6f --- data/etc/services.core.protolog.json | 12 +-- .../java/com/android/server/wm/ActivityRecord.java | 11 +-- .../java/com/android/server/wm/DisplayArea.java | 45 ++++++--- .../java/com/android/server/wm/DisplayContent.java | 53 +++++------ services/core/java/com/android/server/wm/Task.java | 7 +- .../com/android/server/wm/TaskDisplayArea.java | 30 +++--- .../com/android/server/wm/WindowContainer.java | 7 +- .../com/android/server/wm/ActivityRecordTests.java | 2 +- .../src/com/android/server/wm/DisplayAreaTest.java | 68 ++++++++----- .../server/wm/DualDisplayAreaGroupPolicyTest.java | 75 +++++++++++++++ .../android/server/wm/TaskDisplayAreaTests.java | 105 ++++++++++++++++----- .../src/com/android/server/wm/TaskTests.java | 14 ++- .../android/server/wm/WindowContainerTests.java | 13 ++- 13 files changed, 306 insertions(+), 136 deletions(-) diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 1ab5e4bef2bb..278b9580fa2e 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -3907,12 +3907,6 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/TaskDisplayArea.java" }, - "1648338379": { - "message": "Display id=%d is ignoring all orientation requests, return %d", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, "1653025361": { "message": "Register task fragment organizer=%s uid=%d pid=%d", "level": "VERBOSE", @@ -4141,6 +4135,12 @@ "group": "WM_DEBUG_WINDOW_ORGANIZER", "at": "com\/android\/server\/wm\/DisplayAreaPolicyBuilder.java" }, + "1877863087": { + "message": "Display id=%d is ignoring orientation request for %d, return %d", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, "1878927091": { "message": "prepareSurface: No changes in animation for %s", "level": "VERBOSE", diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index d85e510932ed..064f4ee91554 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -7735,10 +7735,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // configuration. This is important to cases where activities with incompatible // orientations launch, or user goes back from an activity of bi-orientation to an // activity with specified orientation. - if (getRequestedOrientation() == SCREEN_ORIENTATION_UNSET) { - return; - } - if (onDescendantOrientationChanged(this)) { // WM Shell can show additional UI elements, e.g. a restart button for size compat mode // so ensure that WM Shell is called when an activity becomes visible. @@ -8311,11 +8307,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } @Override - boolean handlesOrientationChangeFromDescendant() { + boolean handlesOrientationChangeFromDescendant(int orientation) { if (shouldIgnoreOrientationRequests()) { return false; } - return super.handlesOrientationChangeFromDescendant(); + return super.handlesOrientationChangeFromDescendant(orientation); } /** @@ -8337,7 +8333,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // If orientation is respected when insets are applied, then stableBounds will be empty. boolean orientationRespectedWithInsets = orientationRespectedWithInsets(parentBounds, stableBounds); - if (handlesOrientationChangeFromDescendant() && orientationRespectedWithInsets) { + if (orientationRespectedWithInsets + && handlesOrientationChangeFromDescendant(mOrientation)) { // No need to letterbox because of fixed orientation. Display will handle // fixed-orientation requests and a display rotation is enough to respect requested // orientation with insets applied. diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java index 89f1bd043556..a15453e924bd 100644 --- a/services/core/java/com/android/server/wm/DisplayArea.java +++ b/services/core/java/com/android/server/wm/DisplayArea.java @@ -35,6 +35,8 @@ import static com.android.server.wm.DisplayAreaProto.WINDOW_CONTAINER; import static com.android.server.wm.WindowContainerChildProto.DISPLAY_AREA; import android.annotation.Nullable; +import android.content.pm.ActivityInfo; +import android.content.pm.ActivityInfo.ScreenOrientation; import android.content.res.Configuration; import android.graphics.Rect; import android.util.proto.ProtoOutputStream; @@ -142,26 +144,30 @@ public class DisplayArea extends WindowContainer { } @Override + @ScreenOrientation int getOrientation(int candidate) { - mLastOrientationSource = null; - if (getIgnoreOrientationRequest()) { + final int orientation = super.getOrientation(candidate); + if (getIgnoreOrientationRequest(orientation)) { + // In all the other case, mLastOrientationSource will be reassigned to a new value + mLastOrientationSource = null; return SCREEN_ORIENTATION_UNSET; } - - return super.getOrientation(candidate); + return orientation; } @Override - boolean handlesOrientationChangeFromDescendant() { - return !getIgnoreOrientationRequest() - && super.handlesOrientationChangeFromDescendant(); + boolean handlesOrientationChangeFromDescendant(@ScreenOrientation int orientation) { + return !getIgnoreOrientationRequest(orientation) + && super.handlesOrientationChangeFromDescendant(orientation); } @Override - boolean onDescendantOrientationChanged(WindowContainer requestingContainer) { + boolean onDescendantOrientationChanged(@Nullable WindowContainer requestingContainer) { // If this is set to ignore the orientation request, we don't propagate descendant // orientation request. - return !getIgnoreOrientationRequest() + final int orientation = requestingContainer != null + ? requestingContainer.mOrientation : SCREEN_ORIENTATION_UNSET; + return !getIgnoreOrientationRequest(orientation) && super.onDescendantOrientationChanged(requestingContainer); } @@ -225,6 +231,23 @@ public class DisplayArea extends WindowContainer { } } + /** + * @return {@value true} if we need to ignore the orientation in input. + */ + // TODO(b/262366204): Rename getIgnoreOrientationRequest to shouldIgnoreOrientationRequest + boolean getIgnoreOrientationRequest(@ScreenOrientation int orientation) { + // We always respect orientation request for ActivityInfo.SCREEN_ORIENTATION_LOCKED + // ActivityInfo.SCREEN_ORIENTATION_NOSENSOR. + // Main use case why this is important is Camera apps that rely on those + // properties to ensure that they will be able to determine Camera preview + // orientation correctly + if (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED + || orientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) { + return false; + } + return getIgnoreOrientationRequest(); + } + boolean getIgnoreOrientationRequest() { // Adding an exception for when ignoreOrientationRequest is overridden at runtime for all // DisplayArea-s. For example, this is needed for the Kids Mode since many Kids apps aren't @@ -691,11 +714,9 @@ public class DisplayArea extends WindowContainer { } @Override + @ScreenOrientation int getOrientation(int candidate) { mLastOrientationSource = null; - if (getIgnoreOrientationRequest()) { - return SCREEN_ORIENTATION_UNSET; - } // Find a window requesting orientation. final WindowState win = getWindow(mGetOrientingWindow); diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index c6dc24f32837..ffea07cb2bd2 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -1601,13 +1601,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } @Override - boolean onDescendantOrientationChanged(WindowContainer requestingContainer) { + boolean onDescendantOrientationChanged(@Nullable WindowContainer requestingContainer) { final Configuration config = updateOrientation( requestingContainer, false /* forceUpdate */); // If display rotation class tells us that it doesn't consider app requested orientation, // this display won't rotate just because of an app changes its requested orientation. Thus // it indicates that this display chooses not to handle this request. - final boolean handled = handlesOrientationChangeFromDescendant(); + final int orientation = requestingContainer != null ? requestingContainer.mOrientation + : SCREEN_ORIENTATION_UNSET; + final boolean handled = handlesOrientationChangeFromDescendant(orientation); if (config == null) { return handled; } @@ -1630,8 +1632,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } @Override - boolean handlesOrientationChangeFromDescendant() { - return !getIgnoreOrientationRequest() + boolean handlesOrientationChangeFromDescendant(@ScreenOrientation int orientation) { + return !getIgnoreOrientationRequest(orientation) && !getDisplayRotation().isFixedToUserRotation(); } @@ -1732,7 +1734,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp return ROTATION_UNDEFINED; } if (!WindowManagerService.ENABLE_FIXED_ROTATION_TRANSFORM - || getIgnoreOrientationRequest()) { + || getIgnoreOrientationRequest(r.mOrientation)) { return ROTATION_UNDEFINED; } if (r.mOrientation == ActivityInfo.SCREEN_ORIENTATION_BEHIND) { @@ -2740,15 +2742,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp @ScreenOrientation @Override int getOrientation() { - mLastOrientationSource = null; - if (!handlesOrientationChangeFromDescendant()) { - // Return SCREEN_ORIENTATION_UNSPECIFIED so that Display respect sensor rotation - ProtoLog.v(WM_DEBUG_ORIENTATION, - "Display id=%d is ignoring all orientation requests, return %d", - mDisplayId, SCREEN_ORIENTATION_UNSPECIFIED); - return SCREEN_ORIENTATION_UNSPECIFIED; - } - if (mWmService.mDisplayFrozen) { if (mWmService.mPolicy.isKeyguardLocked()) { // Use the last orientation the while the display is frozen with the keyguard @@ -2764,6 +2757,16 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } final int orientation = super.getOrientation(); + + if (!handlesOrientationChangeFromDescendant(orientation)) { + mLastOrientationSource = null; + // Return SCREEN_ORIENTATION_UNSPECIFIED so that Display respect sensor rotation + ProtoLog.v(WM_DEBUG_ORIENTATION, + "Display id=%d is ignoring orientation request for %d, return %d", + mDisplayId, orientation, SCREEN_ORIENTATION_UNSPECIFIED); + return SCREEN_ORIENTATION_UNSPECIFIED; + } + if (orientation == SCREEN_ORIENTATION_UNSET) { // Return SCREEN_ORIENTATION_UNSPECIFIED so that Display respect sensor rotation ProtoLog.v(WM_DEBUG_ORIENTATION, @@ -3890,18 +3893,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp /** Called when the focused {@link TaskDisplayArea} on this display may have changed. */ void onLastFocusedTaskDisplayAreaChanged(@Nullable TaskDisplayArea taskDisplayArea) { - // Only record the TaskDisplayArea that handles orientation request. - if (taskDisplayArea != null && taskDisplayArea.handlesOrientationChangeFromDescendant()) { - mOrientationRequestingTaskDisplayArea = taskDisplayArea; - return; - } - - // If the previous TDA no longer handles orientation request, clear it. - if (mOrientationRequestingTaskDisplayArea != null - && !mOrientationRequestingTaskDisplayArea - .handlesOrientationChangeFromDescendant()) { - mOrientationRequestingTaskDisplayArea = null; - } + mOrientationRequestingTaskDisplayArea = taskDisplayArea; } /** @@ -5104,13 +5096,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } @Override - int getOrientation(int candidate) { - if (getIgnoreOrientationRequest()) { - return SCREEN_ORIENTATION_UNSET; - } - + @ScreenOrientation + int getOrientation(@ScreenOrientation int candidate) { // IME does not participate in orientation. - return candidate; + return getIgnoreOrientationRequest(candidate) ? SCREEN_ORIENTATION_UNSET : candidate; } @Override diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 9367a70cafe3..a422b6d54499 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -144,6 +144,7 @@ import android.app.WindowConfiguration; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; +import android.content.pm.ActivityInfo.ScreenOrientation; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; @@ -2674,8 +2675,8 @@ class Task extends TaskFragment { } @Override - boolean handlesOrientationChangeFromDescendant() { - if (!super.handlesOrientationChangeFromDescendant()) { + boolean handlesOrientationChangeFromDescendant(@ScreenOrientation int orientation) { + if (!super.handlesOrientationChangeFromDescendant(orientation)) { return false; } @@ -2690,7 +2691,7 @@ class Task extends TaskFragment { // Check for leaf Task. // Display won't rotate for the orientation request if the Task/TaskDisplayArea // can't specify orientation. - return canSpecifyOrientation() && getDisplayArea().canSpecifyOrientation(); + return canSpecifyOrientation() && getDisplayArea().canSpecifyOrientation(orientation); } void resize(boolean relayout, boolean forced) { diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index 25b58fa622e7..66b73429225f 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -41,6 +41,7 @@ import android.annotation.Nullable; import android.app.ActivityOptions; import android.app.WindowConfiguration; import android.content.pm.ActivityInfo; +import android.content.pm.ActivityInfo.ScreenOrientation; import android.content.res.Configuration; import android.graphics.Color; import android.os.UserHandle; @@ -633,22 +634,20 @@ final class TaskDisplayArea extends DisplayArea { } @Override - int getOrientation(int candidate) { - mLastOrientationSource = null; - if (getIgnoreOrientationRequest()) { - return SCREEN_ORIENTATION_UNSET; - } - if (!canSpecifyOrientation()) { + @ScreenOrientation + int getOrientation(@ScreenOrientation int candidate) { + final int orientation = super.getOrientation(candidate); + if (!canSpecifyOrientation(orientation)) { + mLastOrientationSource = null; // We only respect orientation of the focused TDA, which can be a child of this TDA. - return reduceOnAllTaskDisplayAreas((taskDisplayArea, orientation) -> { - if (taskDisplayArea == this || orientation != SCREEN_ORIENTATION_UNSET) { - return orientation; + return reduceOnAllTaskDisplayAreas((taskDisplayArea, taskOrientation) -> { + if (taskDisplayArea == this || taskOrientation != SCREEN_ORIENTATION_UNSET) { + return taskOrientation; } return taskDisplayArea.getOrientation(candidate); }, SCREEN_ORIENTATION_UNSET); } - final int orientation = super.getOrientation(candidate); if (orientation != SCREEN_ORIENTATION_UNSET && orientation != SCREEN_ORIENTATION_BEHIND) { ProtoLog.v(WM_DEBUG_ORIENTATION, @@ -1872,12 +1871,11 @@ final class TaskDisplayArea extends DisplayArea { } /** Whether this task display area can request orientation. */ - 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 - // request. - return !getIgnoreOrientationRequest() - && mDisplayContent.getOrientationRequestingTaskDisplayArea() == this; + boolean canSpecifyOrientation(@ScreenOrientation int orientation) { + // Only allow to specify orientation if this TDA is the last focused one on this logical + // display that can request orientation request. + return mDisplayContent.getOrientationRequestingTaskDisplayArea() == this + && !getIgnoreOrientationRequest(orientation); } void clearPreferredTopFocusableRootTask() { diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 64574a7e215b..0fe732c88bf4 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -1459,9 +1459,9 @@ class WindowContainer extends ConfigurationContainer< * @return {@code true} if it handles or will handle orientation change in the future; {@code * false} if it won't handle the change at anytime. */ - boolean handlesOrientationChangeFromDescendant() { + boolean handlesOrientationChangeFromDescendant(int orientation) { final WindowContainer parent = getParent(); - return parent != null && parent.handlesOrientationChangeFromDescendant(); + return parent != null && parent.handlesOrientationChangeFromDescendant(orientation); } /** @@ -1553,7 +1553,8 @@ class WindowContainer extends ConfigurationContainer< // portrait but the task is still in landscape. While updating from display, // the task can be updated to portrait first so the configuration can be // computed in a consistent environment. - && (inMultiWindowMode() || !handlesOrientationChangeFromDescendant())) { + && (inMultiWindowMode() + || !handlesOrientationChangeFromDescendant(orientation))) { // Resolve the requested orientation. onConfigurationChanged(parent.getConfiguration()); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index fcdeb4d51070..19d8894c8d9c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -517,7 +517,7 @@ public class ActivityRecordTests extends WindowTestsBase { // Mimic the behavior that display doesn't handle app's requested orientation. final DisplayContent dc = activity.getTask().getDisplayContent(); doReturn(false).when(dc).onDescendantOrientationChanged(any()); - doReturn(false).when(dc).handlesOrientationChangeFromDescendant(); + doReturn(false).when(dc).handlesOrientationChangeFromDescendant(anyInt()); final int requestedOrientation; switch (newConfig.orientation) { diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java index b87c5a364c82..10540dc5a9ee 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java @@ -18,6 +18,8 @@ package com.android.server.wm; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; @@ -471,29 +473,28 @@ public class DisplayAreaTest extends WindowTestsBase { } @Test - public void testSetIgnoreOrientationRequest() { - final DisplayArea.Tokens area = new DisplayArea.Tokens(mWm, ABOVE_TASKS, "test"); - final WindowToken token = createWindowToken(TYPE_APPLICATION_OVERLAY); - spyOn(token); - doReturn(mock(DisplayContent.class)).when(token).getDisplayContent(); - doNothing().when(token).setParent(any()); - final WindowState win = createWindowState(token); - spyOn(win); - doNothing().when(win).setParent(any()); - win.mAttrs.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; - token.addChild(win, 0); - area.addChild(token); - doReturn(true).when(win).isVisible(); + public void testSetIgnoreOrientationRequest_notCallSuperOnDescendantOrientationChanged() { + final TaskDisplayArea tda = mDisplayContent.getDefaultTaskDisplayArea(); + final Task stack = + new TaskBuilder(mSupervisor).setOnTop(!ON_TOP).setCreateActivity(true).build(); + final ActivityRecord activity = stack.getTopNonFinishingActivity(); - assertEquals(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, area.getOrientation()); + tda.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); - area.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE); - assertEquals(ActivityInfo.SCREEN_ORIENTATION_UNSET, area.getOrientation()); + verify(tda).onDescendantOrientationChanged(any()); + verify(mDisplayContent, never()).onDescendantOrientationChanged(any()); + + tda.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */); + activity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT); + + verify(tda, times(2)).onDescendantOrientationChanged(any()); + verify(mDisplayContent).onDescendantOrientationChanged(any()); } @Test - public void testSetIgnoreOrientationRequest_notCallSuperOnDescendantOrientationChanged() { + public void testSetIgnoreOrientationRequest_callSuperOnDescendantOrientationChangedNoSensor() { final TaskDisplayArea tda = mDisplayContent.getDefaultTaskDisplayArea(); final Task stack = new TaskBuilder(mSupervisor).setOnTop(!ON_TOP).setCreateActivity(true).build(); @@ -501,20 +502,41 @@ public class DisplayAreaTest extends WindowTestsBase { tda.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); - activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE); + activity.setRequestedOrientation(SCREEN_ORIENTATION_NOSENSOR); verify(tda).onDescendantOrientationChanged(any()); - verify(mDisplayContent, never()).onDescendantOrientationChanged(any()); + verify(mDisplayContent).onDescendantOrientationChanged(any()); tda.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */); - activity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT); + activity.setRequestedOrientation(SCREEN_ORIENTATION_NOSENSOR); - verify(tda, times(2)).onDescendantOrientationChanged(any()); + verify(tda).onDescendantOrientationChanged(any()); + verify(mDisplayContent).onDescendantOrientationChanged(any()); + } + + @Test + public void testSetIgnoreOrientationRequest_callSuperOnDescendantOrientationChangedLocked() { + final TaskDisplayArea tda = mDisplayContent.getDefaultTaskDisplayArea(); + final Task stack = + new TaskBuilder(mSupervisor).setOnTop(!ON_TOP).setCreateActivity(true).build(); + final ActivityRecord activity = stack.getTopNonFinishingActivity(); + + tda.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + + activity.setRequestedOrientation(SCREEN_ORIENTATION_LOCKED); + + verify(tda).onDescendantOrientationChanged(any()); + verify(mDisplayContent).onDescendantOrientationChanged(any()); + + tda.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */); + activity.setRequestedOrientation(SCREEN_ORIENTATION_LOCKED); + + verify(tda).onDescendantOrientationChanged(any()); verify(mDisplayContent).onDescendantOrientationChanged(any()); } @Test - public void testSetIgnoreOrientationRequest_updateOrientationRequestingTaskDisplayArea() { + public void testGetOrientationRequestingTaskDisplayArea_updateOrientationTaskDisplayArea() { final TaskDisplayArea tda = mDisplayContent.getDefaultTaskDisplayArea(); final Task stack = new TaskBuilder(mSupervisor).setOnTop(!ON_TOP).setCreateActivity(true).build(); @@ -526,7 +548,7 @@ public class DisplayAreaTest extends WindowTestsBase { // TDA is no longer handling orientation request, clear the last focused TDA. tda.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); - assertThat(mDisplayContent.getOrientationRequestingTaskDisplayArea()).isNull(); + assertThat(mDisplayContent.getOrientationRequestingTaskDisplayArea()).isEqualTo(tda); // TDA now handles orientation request, update last focused TDA based on the focused app. tda.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */); 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 75c5b6e13777..4eaae9fb8240 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java @@ -17,6 +17,8 @@ package com.android.server.wm; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; @@ -169,6 +171,30 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase { verify(mDisplay, never()).onDescendantOrientationChanged(any()); } + @Test + public void testIgnoreOrientationRequest_displayReceiveOrientationChangeForNoSensor() { + mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda); + + prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_NOSENSOR); + + verify(mFirstRoot).onDescendantOrientationChanged(any()); + verify(mDisplay).onDescendantOrientationChanged(any()); + } + + @Test + public void testIgnoreOrientationRequest_displayReceiveOrientationChangeForLocked() { + mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda); + + prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_LOCKED); + + verify(mFirstRoot).onDescendantOrientationChanged(any()); + verify(mDisplay).onDescendantOrientationChanged(any()); + } + @Test public void testLaunchPortraitApp_fillsDisplayAreaGroup() { mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); @@ -221,6 +247,21 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase { newTaskBounds.height() * newTaskBounds.height() / newTaskBounds.width()); } + @Test + public void testLaunchNoSensorApp_noSizeCompatAfterRotation() { + mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda); + + prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_NOSENSOR); + assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse(); + assertThat(mFirstActivity.inSizeCompatMode()).isFalse(); + + rotateDisplay(mDisplay, ROTATION_90); + assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse(); + assertThat(mFirstActivity.inSizeCompatMode()).isFalse(); + } + @Test public void testLaunchLandscapeApp_activityIsLetterboxForFixedOrientationInDisplayAreaGroup() { mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); @@ -242,6 +283,26 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase { .isEqualTo(dagBounds.width() * dagBounds.width() / dagBounds.height()); } + @Test + public void testLaunchNoSensorApp_activityIsNotLetterboxForFixedOrientationDisplayAreaGroup() { + mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda); + + prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_NOSENSOR); + assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse(); + } + + @Test + public void testLaunchLockedApp_activityIsNotLetterboxForFixedOrientationInDisplayAreaGroup() { + mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda); + + prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_LOCKED); + assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse(); + } + @Test public void testLaunchLandscapeApp_fixedOrientationLetterboxBecomesSizeCompatAfterRotation() { mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); @@ -271,6 +332,20 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase { assertThat(newActivityBounds.height()).isEqualTo(activityBounds.height()); } + @Test + public void testLaunchNoSensorApp_fixedOrientationLetterboxBecomesSizeCompatAfterRotation() { + mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda); + + prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_NOSENSOR); + + rotateDisplay(mDisplay, ROTATION_90); + + assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse(); + assertThat(mFirstActivity.inSizeCompatMode()).isFalse(); + } + @Test public void testPlaceImeContainer_reparentToTargetDisplayAreaGroup() { setupImeWindow(); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java index 91f8d8d186c6..d43805ab9554 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java @@ -29,8 +29,9 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT; import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; 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_UNSET; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; @@ -422,24 +423,63 @@ public class TaskDisplayAreaTests extends WindowTestsBase { // Activity on TDA1 is focused mDisplayContent.setFocusedApp(firstActivity); - assertThat(firstTaskDisplayArea.canSpecifyOrientation()).isTrue(); - assertThat(secondTaskDisplayArea.canSpecifyOrientation()).isFalse(); + final int testOrientation = SCREEN_ORIENTATION_PORTRAIT; + + assertThat(firstTaskDisplayArea.canSpecifyOrientation(testOrientation)).isTrue(); + assertThat(secondTaskDisplayArea.canSpecifyOrientation(testOrientation)).isFalse(); // No focused app, TDA1 is still recorded as last focused. mDisplayContent.setFocusedApp(null); - assertThat(firstTaskDisplayArea.canSpecifyOrientation()).isTrue(); - assertThat(secondTaskDisplayArea.canSpecifyOrientation()).isFalse(); + assertThat(firstTaskDisplayArea.canSpecifyOrientation(testOrientation)).isTrue(); + assertThat(secondTaskDisplayArea.canSpecifyOrientation(testOrientation)).isFalse(); // Activity on TDA2 is focused mDisplayContent.setFocusedApp(secondActivity); - assertThat(firstTaskDisplayArea.canSpecifyOrientation()).isFalse(); - assertThat(secondTaskDisplayArea.canSpecifyOrientation()).isTrue(); + assertThat(firstTaskDisplayArea.canSpecifyOrientation(testOrientation)).isFalse(); + assertThat(secondTaskDisplayArea.canSpecifyOrientation(testOrientation)).isTrue(); + } + + @Test + public void testCanSpecifyOrientation() { + final TaskDisplayArea firstTaskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea(); + final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea( + mDisplayContent, mRootWindowContainer.mWmService, "TestTaskDisplayArea", + FEATURE_VENDOR_FIRST); + final Task firstRootTask = firstTaskDisplayArea.createRootTask( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); + final Task secondRootTask = secondTaskDisplayArea.createRootTask( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); + final ActivityRecord firstActivity = new ActivityBuilder(mAtm) + .setTask(firstRootTask).build(); + final ActivityRecord secondActivity = new ActivityBuilder(mAtm) + .setTask(secondRootTask).build(); + firstTaskDisplayArea.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + secondTaskDisplayArea.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */); + + final int testOrientation = SCREEN_ORIENTATION_PORTRAIT; + + // Activity on TDA1 is focused, but TDA1 cannot specify orientation because + // ignoreOrientationRequest is true + // Activity on TDA2 has ignoreOrientationRequest false but it doesn't have focus so it + // cannot specify orientation + mDisplayContent.setFocusedApp(firstActivity); + + assertThat(firstTaskDisplayArea.canSpecifyOrientation(testOrientation)).isFalse(); + assertThat(secondTaskDisplayArea.canSpecifyOrientation(testOrientation)).isFalse(); + + // Activity on TDA1 is not focused, and so it cannot specify orientation + // Activity on TDA2 is focused, and it can specify orientation because + // ignoreOrientationRequest is false + mDisplayContent.setFocusedApp(secondActivity); + + assertThat(firstTaskDisplayArea.canSpecifyOrientation(testOrientation)).isFalse(); + assertThat(secondTaskDisplayArea.canSpecifyOrientation(testOrientation)).isTrue(); } @Test - public void testIsLastFocused_onlyCountIfTaskDisplayAreaHandlesOrientationRequest() { + public void testCanSpecifyOrientationNoSensor() { final TaskDisplayArea firstTaskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea(); final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea( mDisplayContent, mRootWindowContainer.mWmService, "TestTaskDisplayArea", @@ -455,34 +495,51 @@ public class TaskDisplayAreaTests extends WindowTestsBase { firstTaskDisplayArea.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); secondTaskDisplayArea.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */); - // Activity on TDA1 is focused, but TDA1 doesn't respect orientation request + final int testOrientation = SCREEN_ORIENTATION_NOSENSOR; + + // ignoreOrientationRequest is always false for SCREEN_ORIENTATION_NOSENSOR so + // only the TDAs with focus can specify orientations mDisplayContent.setFocusedApp(firstActivity); - assertThat(firstTaskDisplayArea.canSpecifyOrientation()).isFalse(); - assertThat(secondTaskDisplayArea.canSpecifyOrientation()).isFalse(); + assertThat(firstTaskDisplayArea.canSpecifyOrientation(testOrientation)).isTrue(); + assertThat(secondTaskDisplayArea.canSpecifyOrientation(testOrientation)).isFalse(); - // Activity on TDA2 is focused, and TDA2 respects orientation request mDisplayContent.setFocusedApp(secondActivity); - assertThat(firstTaskDisplayArea.canSpecifyOrientation()).isFalse(); - assertThat(secondTaskDisplayArea.canSpecifyOrientation()).isTrue(); + assertThat(firstTaskDisplayArea.canSpecifyOrientation(testOrientation)).isFalse(); + assertThat(secondTaskDisplayArea.canSpecifyOrientation(testOrientation)).isTrue(); } @Test - public void testIgnoreOrientationRequest() { - final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea(); - final Task task = taskDisplayArea.createRootTask( + public void testCanSpecifyOrientationLocked() { + final TaskDisplayArea firstTaskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea(); + final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea( + mDisplayContent, mRootWindowContainer.mWmService, "TestTaskDisplayArea", + FEATURE_VENDOR_FIRST); + final Task firstRootTask = firstTaskDisplayArea.createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); - final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build(); + final Task secondRootTask = secondTaskDisplayArea.createRootTask( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); + final ActivityRecord firstActivity = new ActivityBuilder(mAtm) + .setTask(firstRootTask).build(); + final ActivityRecord secondActivity = new ActivityBuilder(mAtm) + .setTask(secondRootTask).build(); + firstTaskDisplayArea.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + secondTaskDisplayArea.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */); - mDisplayContent.setFocusedApp(activity); - activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE); + final int testOrientation = SCREEN_ORIENTATION_LOCKED; - assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE); + // ignoreOrientationRequest is always false for SCREEN_ORIENTATION_NOSENSOR so + // only the TDAs with focus can specify orientations + mDisplayContent.setFocusedApp(firstActivity); - taskDisplayArea.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + assertThat(firstTaskDisplayArea.canSpecifyOrientation(testOrientation)).isTrue(); + assertThat(secondTaskDisplayArea.canSpecifyOrientation(testOrientation)).isFalse(); + + mDisplayContent.setFocusedApp(secondActivity); - assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSET); + assertThat(firstTaskDisplayArea.canSpecifyOrientation(testOrientation)).isFalse(); + assertThat(secondTaskDisplayArea.canSpecifyOrientation(testOrientation)).isTrue(); } @Test 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 19e3246cf02c..9cd80a34b714 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java @@ -57,6 +57,7 @@ import static org.junit.Assert.assertNull; 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.eq; import static org.mockito.ArgumentMatchers.same; @@ -393,12 +394,16 @@ public class TaskTests extends WindowTestsBase { leafTask1.getWindowConfiguration().setActivityType(ACTIVITY_TYPE_HOME); leafTask2.getWindowConfiguration().setActivityType(ACTIVITY_TYPE_STANDARD); + // We need to use an orientation that is not an exception for the + // ignoreOrientationRequest flag. + final int orientation = SCREEN_ORIENTATION_PORTRAIT; + assertEquals(leafTask2, rootTask.getTopChild()); - assertTrue(rootTask.handlesOrientationChangeFromDescendant()); + assertTrue(rootTask.handlesOrientationChangeFromDescendant(orientation)); // Treat orientation request from home as handled. - assertTrue(leafTask1.handlesOrientationChangeFromDescendant()); + assertTrue(leafTask1.handlesOrientationChangeFromDescendant(orientation)); // Orientation request from standard activity in multi window will not be handled. - assertFalse(leafTask2.handlesOrientationChangeFromDescendant()); + assertFalse(leafTask2.handlesOrientationChangeFromDescendant(orientation)); } @Test @@ -655,7 +660,8 @@ public class TaskTests extends WindowTestsBase { doReturn(parentWindowContainer).when(task).getParent(); doReturn(display.getDefaultTaskDisplayArea()).when(task).getDisplayArea(); doReturn(rootTask).when(task).getRootTask(); - doReturn(true).when(parentWindowContainer).handlesOrientationChangeFromDescendant(); + doReturn(true).when(parentWindowContainer) + .handlesOrientationChangeFromDescendant(anyInt()); // Setting app to fixed portrait fits within parent, but Task shouldn't adjust the // bounds because its parent says it will handle it at a later time. diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java index 98a28cfbe22c..ebf316697d3a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java @@ -662,13 +662,13 @@ public class WindowContainerTests extends WindowTestsBase { public void testSetOrientation() { final TestWindowContainer root = spy(new TestWindowContainerBuilder(mWm).build()); final TestWindowContainer child = spy(root.addChildWindow()); - doReturn(true).when(root).handlesOrientationChangeFromDescendant(); + doReturn(true).when(root).handlesOrientationChangeFromDescendant(anyInt()); child.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FULLSCREEN); child.setOrientation(SCREEN_ORIENTATION_PORTRAIT); // The ancestor should decide whether to dispatch the configuration change. verify(child, never()).onConfigurationChanged(any()); - doReturn(false).when(root).handlesOrientationChangeFromDescendant(); + doReturn(false).when(root).handlesOrientationChangeFromDescendant(anyInt()); child.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); // The ancestor doesn't handle the request so the descendant applies the change directly. verify(child).onConfigurationChanged(any()); @@ -843,11 +843,14 @@ public class WindowContainerTests extends WindowTestsBase { final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); final TestWindowContainer root = spy(builder.build()); + // We use an orientation that is not an exception for the ignoreOrientationRequest flag + final int orientation = SCREEN_ORIENTATION_PORTRAIT; + final TestWindowContainer child = root.addChildWindow(); - assertFalse(child.handlesOrientationChangeFromDescendant()); + assertFalse(child.handlesOrientationChangeFromDescendant(orientation)); - Mockito.doReturn(true).when(root).handlesOrientationChangeFromDescendant(); - assertTrue(child.handlesOrientationChangeFromDescendant()); + Mockito.doReturn(true).when(root).handlesOrientationChangeFromDescendant(anyInt()); + assertTrue(child.handlesOrientationChangeFromDescendant(orientation)); } @Test -- cgit v1.2.3-59-g8ed1b