diff options
7 files changed, 142 insertions, 31 deletions
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 217de84cfc3e..6b80bb60ec67 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -259,6 +259,12 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/WindowState.java" }, + "-1741065110": { + "message": "No app is requesting an orientation, return %d for display id=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, "-1730156332": { "message": "Display id=%d rotation changed to %d from %d, lastOrientation=%d", "level": "VERBOSE", @@ -1909,6 +1915,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowToken.java" }, + "845234215": { + "message": "App is requesting an orientation, return %d for display id=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, "853091290": { "message": "Moved stack=%s behind stack=%s", "level": "DEBUG", @@ -2179,12 +2191,6 @@ "group": "WM_DEBUG_IME", "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" }, - "1381227466": { - "message": "App is requesting an orientation, return %d for display id=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/TaskDisplayArea.java" - }, "1401295262": { "message": "Mode default, asking user", "level": "WARN", @@ -2371,12 +2377,6 @@ "group": "WM_DEBUG_RESIZE", "at": "com\/android\/server\/wm\/WindowState.java" }, - "1640436199": { - "message": "No app is requesting an orientation, return %d for display id=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/TaskDisplayArea.java" - }, "1653210583": { "message": "Removing app %s delayed=%b animation=%s animating=%b", "level": "VERBOSE", diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 0044d7498614..0be5cbe5199c 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -28,6 +28,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.content.res.Configuration.ORIENTATION_UNDEFINED; @@ -464,6 +466,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp */ ActivityRecord mFocusedApp = null; + /** The last focused {@link TaskDisplayArea} on this display. */ + private TaskDisplayArea mLastFocusedTaskDisplayArea = null; + /** * The launching activity which is using fixed rotation transformation. * @@ -2327,7 +2332,21 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp return getLastOrientation(); } } - return super.getOrientation(); + + final int orientation = super.getOrientation(); + if (orientation != SCREEN_ORIENTATION_UNSET && orientation != SCREEN_ORIENTATION_BEHIND) { + ProtoLog.v(WM_DEBUG_ORIENTATION, + "App is requesting an orientation, return %d for display id=%d", + orientation, mDisplayId); + return orientation; + } + + ProtoLog.v(WM_DEBUG_ORIENTATION, + "No app is requesting an orientation, return %d for display id=%d", + getLastOrientation(), mDisplayId); + // The next app has not been requested to be visible, so we keep the current orientation + // to prevent freezing/unfreezing the display too early. + return getLastOrientation(); } void updateDisplayInfo() { @@ -3202,6 +3221,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp throw new IllegalStateException(newFocus + " is not on " + getName() + " but " + ((appDisplay != null) ? appDisplay.getName() : "none")); } + + // Called even if the focused app is not changed in case the app is moved to a different + // TaskDisplayArea. + setLastFocusedTaskDisplayArea(newFocus.getDisplayArea()); } if (mFocusedApp == newFocus) { return false; @@ -3214,6 +3237,19 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp return true; } + /** Called when the focused {@link TaskDisplayArea} on this display may have changed. */ + @VisibleForTesting + void setLastFocusedTaskDisplayArea(@Nullable TaskDisplayArea taskDisplayArea) { + if (taskDisplayArea != null) { + mLastFocusedTaskDisplayArea = taskDisplayArea; + } + } + + /** Gets the last focused {@link TaskDisplayArea} on this display. */ + TaskDisplayArea getLastFocusedTaskDisplayArea() { + return mLastFocusedTaskDisplayArea; + } + /** Updates the layer assignment of windows on this display. */ void assignWindowLayers(boolean setLayoutNeeded) { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "assignWindowLayers"); diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index 0d77d1c2cd89..c11624c92117 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -29,12 +29,10 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMAR import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.app.WindowConfiguration.isSplitScreenWindowingMode; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; -import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS; @@ -645,6 +643,12 @@ final class TaskDisplayArea extends DisplayArea<Task> { @Override int getOrientation(int candidate) { + // Only allow to specify orientation if this TDA has the focus. + // TODO(b/155431879) Add option to never allow a TDA to specify orientation. + if (!isLastFocused()) { + return SCREEN_ORIENTATION_UNSET; + } + if (isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) { // Apps and their containers are not allowed to specify an orientation while using // root tasks...except for the home stack if it is not resizable and currently @@ -671,21 +675,7 @@ final class TaskDisplayArea extends DisplayArea<Task> { return SCREEN_ORIENTATION_UNSPECIFIED; } - final int orientation = super.getOrientation(candidate); - if (orientation != SCREEN_ORIENTATION_UNSET - && orientation != SCREEN_ORIENTATION_BEHIND) { - ProtoLog.v(WM_DEBUG_ORIENTATION, - "App is requesting an orientation, return %d for display id=%d", - orientation, mDisplayContent.mDisplayId); - return orientation; - } - - ProtoLog.v(WM_DEBUG_ORIENTATION, - "No app is requesting an orientation, return %d for display id=%d", - mDisplayContent.getLastOrientation(), mDisplayContent.mDisplayId); - // The next app has not been requested to be visible, so we keep the current orientation - // to prevent freezing/unfreezing the display too early. - return mDisplayContent.getLastOrientation(); + return super.getOrientation(candidate); } @Override @@ -1880,6 +1870,12 @@ final class TaskDisplayArea extends DisplayArea<Task> { return lastReparentedStack; } + /** Whether this task display area is the last focused one on this logical display. */ + @VisibleForTesting + boolean isLastFocused() { + return mDisplayContent.getLastFocusedTaskDisplayArea() == this; + } + @Override protected boolean isTaskDisplayArea() { return true; 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 6a29c5b5424a..da3319acca24 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java +++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java @@ -318,6 +318,9 @@ public class SystemServicesTestRule implements TestRule { display.setDisplayWindowingMode(WINDOWING_MODE_FULLSCREEN); spyOn(display); final TaskDisplayArea taskDisplayArea = display.getDefaultTaskDisplayArea(); + + // Set the default focused TDA. + display.setLastFocusedTaskDisplayArea(taskDisplayArea); spyOn(taskDisplayArea); final Task homeStack = taskDisplayArea.getStack( 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 bc3b3a4d7ad1..e71f7ec54b0e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java @@ -29,6 +29,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMAR import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; +import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; @@ -242,6 +243,40 @@ public class TaskDisplayAreaTests extends WindowTestsBase { assertEquals(rootWindowContainer.getOrientation(), rootHomeTask.getOrientation()); } + @Test + public void testIsLastFocused() { + final TaskDisplayArea firstTaskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea(); + final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea( + mDisplayContent, mRootWindowContainer.mWmService, "TestTaskDisplayArea", + FEATURE_VENDOR_FIRST); + final Task firstStack = firstTaskDisplayArea.createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); + final Task secondStack = secondTaskDisplayArea.createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); + final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setCreateTask(true) + .setStack(firstStack).build(); + final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setCreateTask(true) + .setStack(secondStack).build(); + + // Activity on TDA1 is focused + mDisplayContent.setFocusedApp(firstActivity); + + assertThat(firstTaskDisplayArea.isLastFocused()).isTrue(); + assertThat(secondTaskDisplayArea.isLastFocused()).isFalse(); + + // No focused app, TDA1 is still recorded as last focused. + mDisplayContent.setFocusedApp(null); + + assertThat(firstTaskDisplayArea.isLastFocused()).isTrue(); + assertThat(secondTaskDisplayArea.isLastFocused()).isFalse(); + + // Activity on TDA2 is focused + mDisplayContent.setFocusedApp(secondActivity); + + assertThat(firstTaskDisplayArea.isLastFocused()).isFalse(); + assertThat(secondTaskDisplayArea.isLastFocused()).isTrue(); + } + private void assertGetOrCreateStack(int windowingMode, int activityType, Task candidateTask, boolean reuseCandidate) { final TaskDisplayArea taskDisplayArea = candidateTask.getDisplayArea(); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java index a908bfef98de..d2b7ac4c3b24 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java @@ -33,6 +33,7 @@ import static android.util.DisplayMetrics.DENSITY_DEFAULT; import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_ENABLED; import static android.view.Surface.ROTATION_0; import static android.view.Surface.ROTATION_90; +import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; @@ -1001,7 +1002,7 @@ public class TaskRecordTests extends WindowTestsBase { public void testNotSpecifyOrientationByFloatingTask() { final Task task = getTestTask(); final ActivityRecord activity = task.getTopMostActivity(); - final WindowContainer<?> taskDisplayArea = task.getParent(); + final TaskDisplayArea taskDisplayArea = task.getDisplayArea(); activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE); assertEquals(SCREEN_ORIENTATION_LANDSCAPE, taskDisplayArea.getOrientation()); @@ -1012,6 +1013,42 @@ public class TaskRecordTests extends WindowTestsBase { } @Test + public void testNotSpecifyOrientation_taskDisplayAreaNotFocused() { + final TaskDisplayArea firstTaskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea(); + final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea( + mDisplayContent, mRootWindowContainer.mWmService, "TestTaskDisplayArea", + FEATURE_VENDOR_FIRST); + final Task firstStack = firstTaskDisplayArea.createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); + final Task secondStack = secondTaskDisplayArea.createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); + final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setCreateTask(true) + .setStack(firstStack).build(); + final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setCreateTask(true) + .setStack(secondStack).build(); + firstActivity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE); + secondActivity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT); + + // Activity on TDA1 is focused + mDisplayContent.setFocusedApp(firstActivity); + + assertEquals(SCREEN_ORIENTATION_LANDSCAPE, firstTaskDisplayArea.getOrientation()); + assertEquals(SCREEN_ORIENTATION_UNSET, secondTaskDisplayArea.getOrientation()); + + // No focused app, TDA1 is still recorded as last focused. + mDisplayContent.setFocusedApp(null); + + assertEquals(SCREEN_ORIENTATION_LANDSCAPE, firstTaskDisplayArea.getOrientation()); + assertEquals(SCREEN_ORIENTATION_UNSET, secondTaskDisplayArea.getOrientation()); + + // Activity on TDA2 is focused + mDisplayContent.setFocusedApp(secondActivity); + + assertEquals(SCREEN_ORIENTATION_UNSET, firstTaskDisplayArea.getOrientation()); + assertEquals(SCREEN_ORIENTATION_PORTRAIT, secondTaskDisplayArea.getOrientation()); + } + + @Test public void testNotifyOrientationChangeCausedByConfigurationChange() { final Task task = getTestTask(); final ActivityRecord activity = task.getTopMostActivity(); 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 213c1f52aa37..ee16a76bcff8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java @@ -156,6 +156,10 @@ class TestDisplayContent extends DisplayContent { // threads immediately after adding it to hierarchy. Calling doAnswer() type of stubbing // reduces chance of races, but still doesn't eliminate race conditions. mService.mRootWindowContainer.addChild(newDisplay, mPosition); + + // Set the default focused TDA. + newDisplay.setLastFocusedTaskDisplayArea(newDisplay.getDefaultTaskDisplayArea()); + return newDisplay; } } |