diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java index cd3f322781659..15483cb90ce21 100644 --- a/services/core/java/com/android/server/wm/DisplayArea.java +++ b/services/core/java/com/android/server/wm/DisplayArea.java @@ -174,6 +174,13 @@ public class DisplayArea extends WindowContainer { return false; } + if (mDisplayContent.mFocusedApp != null) { + // We record the last focused TDA that respects orientation request, check if this + // change may affect it. + mDisplayContent.onLastFocusedTaskDisplayAreaChanged( + mDisplayContent.mFocusedApp.getDisplayArea()); + } + // The orientation request from this DA may now be respected. if (!ignoreOrientationRequest) { return mDisplayContent.updateOrientation(); diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 1d2cd0a0a350c..8e434cef3ca65 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -488,8 +488,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp */ ActivityRecord mFocusedApp = null; - /** The last focused {@link TaskDisplayArea} on this display. */ - private TaskDisplayArea mLastFocusedTaskDisplayArea = null; + /** + * We only respect the orientation request from apps below this {@link TaskDisplayArea}. + * It is the last focused {@link TaskDisplayArea} on this display that handles orientation + * request. + */ + @Nullable + private TaskDisplayArea mOrientationRequestingTaskDisplayArea = null; /** * The launching activity which is using fixed rotation transformation. @@ -3325,7 +3330,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // Called even if the focused app is not changed in case the app is moved to a different // TaskDisplayArea. - setLastFocusedTaskDisplayArea(newFocus.getDisplayArea()); + onLastFocusedTaskDisplayAreaChanged(newFocus.getDisplayArea()); } if (mFocusedApp == newFocus) { return false; @@ -3339,16 +3344,27 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } /** Called when the focused {@link TaskDisplayArea} on this display may have changed. */ - @VisibleForTesting - void setLastFocusedTaskDisplayArea(@Nullable TaskDisplayArea taskDisplayArea) { - if (taskDisplayArea != null) { - mLastFocusedTaskDisplayArea = taskDisplayArea; + 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; } } - /** Gets the last focused {@link TaskDisplayArea} on this display. */ - TaskDisplayArea getLastFocusedTaskDisplayArea() { - return mLastFocusedTaskDisplayArea; + /** + * Gets the {@link TaskDisplayArea} that we respect orientation requests from apps below it. + */ + @Nullable + TaskDisplayArea getOrientationRequestingTaskDisplayArea() { + return mOrientationRequestingTaskDisplayArea; } /** Updates the layer assignment of windows on this display. */ diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index 4498a8c82583d..9425602763c5d 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -641,9 +641,7 @@ final class TaskDisplayArea extends DisplayArea { @Override int getOrientation(int candidate) { mLastOrientationSource = null; - // Only allow to specify orientation if this TDA is not set to ignore orientation request, - // and it has the focus. - if (mIgnoreOrientationRequest || !isLastFocused()) { + if (!canSpecifyOrientation()) { return SCREEN_ORIENTATION_UNSET; } @@ -1918,10 +1916,14 @@ final class TaskDisplayArea extends DisplayArea { return lastReparentedStack; } - /** Whether this task display area is the last focused one on this logical display. */ + /** Whether this task display area can request orientation. */ @VisibleForTesting - boolean isLastFocused() { - return mDisplayContent.getLastFocusedTaskDisplayArea() == this; + 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 !mIgnoreOrientationRequest + && mDisplayContent.getOrientationRequestingTaskDisplayArea() == this; } @Override diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java index bc91c709aeb1d..f536cd0b0ed48 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java @@ -61,7 +61,7 @@ public class DisplayAreaGroupTest extends WindowTestsBase { mTaskDisplayArea = new TaskDisplayArea( mDisplayContent, mWm, "TDA1", FEATURE_VENDOR_FIRST + 1); mDisplayAreaGroup.addChild(mTaskDisplayArea, POSITION_TOP); - mDisplayContent.setLastFocusedTaskDisplayArea(mTaskDisplayArea); + mDisplayContent.onLastFocusedTaskDisplayAreaChanged(mTaskDisplayArea); } @Test 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 025c5a6bb1807..6f5a874114eac 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java @@ -458,8 +458,7 @@ public class DisplayAreaTest extends WindowTestsBase { @Test public void testSetIgnoreOrientationRequest_notCallSuperOnDescendantOrientationChanged() { - final TaskDisplayArea tda = - mDisplayContent.getDefaultTaskDisplayArea(); + final TaskDisplayArea tda = mDisplayContent.getDefaultTaskDisplayArea(); final Task stack = new TaskBuilder(mSupervisor).setOnTop(!ON_TOP).setCreateActivity(true).build(); final ActivityRecord activity = stack.getTopNonFinishingActivity(); @@ -478,6 +477,27 @@ public class DisplayAreaTest extends WindowTestsBase { verify(mDisplayContent).onDescendantOrientationChanged(any()); } + @Test + public void testSetIgnoreOrientationRequest_updateOrientationRequestingTaskDisplayArea() { + final TaskDisplayArea tda = mDisplayContent.getDefaultTaskDisplayArea(); + final Task stack = + new TaskBuilder(mSupervisor).setOnTop(!ON_TOP).setCreateActivity(true).build(); + final ActivityRecord activity = stack.getTopNonFinishingActivity(); + + mDisplayContent.setFocusedApp(activity); + assertThat(mDisplayContent.getOrientationRequestingTaskDisplayArea()).isEqualTo(tda); + + // TDA is no longer handling orientation request, clear the last focused TDA. + tda.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + + assertThat(mDisplayContent.getOrientationRequestingTaskDisplayArea()).isNull(); + + // TDA now handles orientation request, update last focused TDA based on the focused app. + tda.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */); + + assertThat(mDisplayContent.getOrientationRequestingTaskDisplayArea()).isEqualTo(tda); + } + private static class TestDisplayArea extends DisplayArea { private TestDisplayArea(WindowManagerService wms, Rect bounds) { super(wms, ANY, "half display area"); diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java index 83e3d22345e1d..e1bc90a2551c7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java +++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java @@ -325,7 +325,7 @@ public class SystemServicesTestRule implements TestRule { final TaskDisplayArea taskDisplayArea = display.getDefaultTaskDisplayArea(); // Set the default focused TDA. - display.setLastFocusedTaskDisplayArea(taskDisplayArea); + display.onLastFocusedTaskDisplayAreaChanged(taskDisplayArea); spyOn(taskDisplayArea); final Task homeStack = taskDisplayArea.getRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME); 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 d80f816424740..1c93e0f7e185d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java @@ -262,20 +262,50 @@ public class TaskDisplayAreaTests extends WindowTestsBase { // Activity on TDA1 is focused mDisplayContent.setFocusedApp(firstActivity); - assertThat(firstTaskDisplayArea.isLastFocused()).isTrue(); - assertThat(secondTaskDisplayArea.isLastFocused()).isFalse(); + assertThat(firstTaskDisplayArea.canSpecifyOrientation()).isTrue(); + assertThat(secondTaskDisplayArea.canSpecifyOrientation()).isFalse(); // No focused app, TDA1 is still recorded as last focused. mDisplayContent.setFocusedApp(null); - assertThat(firstTaskDisplayArea.isLastFocused()).isTrue(); - assertThat(secondTaskDisplayArea.isLastFocused()).isFalse(); + assertThat(firstTaskDisplayArea.canSpecifyOrientation()).isTrue(); + assertThat(secondTaskDisplayArea.canSpecifyOrientation()).isFalse(); // Activity on TDA2 is focused mDisplayContent.setFocusedApp(secondActivity); - assertThat(firstTaskDisplayArea.isLastFocused()).isFalse(); - assertThat(secondTaskDisplayArea.isLastFocused()).isTrue(); + assertThat(firstTaskDisplayArea.canSpecifyOrientation()).isFalse(); + assertThat(secondTaskDisplayArea.canSpecifyOrientation()).isTrue(); + } + + @Test + public void testIsLastFocused_onlyCountIfTaskDisplayAreaHandlesOrientationRequest() { + final TaskDisplayArea firstTaskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea(); + final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea( + mDisplayContent, mRootWindowContainer.mWmService, "TestTaskDisplayArea", + FEATURE_VENDOR_FIRST); + final Task firstStack = firstTaskDisplayArea.createRootTask( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); + final Task secondStack = secondTaskDisplayArea.createRootTask( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); + final ActivityRecord firstActivity = new ActivityBuilder(mAtm) + .setTask(firstStack).build(); + final ActivityRecord secondActivity = new ActivityBuilder(mAtm) + .setTask(secondStack).build(); + firstTaskDisplayArea.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + secondTaskDisplayArea.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */); + + // Activity on TDA1 is focused, but TDA1 doesn't respect orientation request + mDisplayContent.setFocusedApp(firstActivity); + + assertThat(firstTaskDisplayArea.canSpecifyOrientation()).isFalse(); + assertThat(secondTaskDisplayArea.canSpecifyOrientation()).isFalse(); + + // Activity on TDA2 is focused, and TDA2 respects orientation request + mDisplayContent.setFocusedApp(secondActivity); + + assertThat(firstTaskDisplayArea.canSpecifyOrientation()).isFalse(); + assertThat(secondTaskDisplayArea.canSpecifyOrientation()).isTrue(); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java index e95efe785e8c3..59e79d728d6ff 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java @@ -158,7 +158,7 @@ class TestDisplayContent extends DisplayContent { mService.mRootWindowContainer.addChild(newDisplay, mPosition); // Set the default focused TDA. - newDisplay.setLastFocusedTaskDisplayArea(newDisplay.getDefaultTaskDisplayArea()); + newDisplay.onLastFocusedTaskDisplayAreaChanged(newDisplay.getDefaultTaskDisplayArea()); return newDisplay; }