diff options
| author | 2020-09-14 12:45:11 -0700 | |
|---|---|---|
| committer | 2020-09-22 17:01:39 -0700 | |
| commit | 3dbefb99c4669b4e8a0b28296ac18d8064213ea0 (patch) | |
| tree | 2500a73b396d034ba79c4a43750a68de07340bff | |
| parent | f747948b6d1fc080bcd11c83555eaafd4ed7441d (diff) | |
Add option to always ignore orientation request
(2/n Orientation on DisplayAreaGroup)
When the option is set to true, the TDA will ignore all the
fixed-orientation request from apps.
This can be used on duo display device, so that the logical display will
not be rotated when launching a fixed-orientation app on one of the
display.
Bug: 155431879
Test: manual: test with dual-display-area policy
Test: atest WmTests:TaskDisplayAreaTests
Test: atest WmTests:WindowOrganizerTests
Change-Id: I3f0ea1415523926195b51fe28744974a9b64d803
5 files changed, 143 insertions, 4 deletions
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index 8be37e9e492d..ba901549f2b5 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -238,6 +238,22 @@ public final class WindowContainerTransaction implements Parcelable { } /** + * Sets whether a container should ignore the orientation request from apps below it. It + * currently only applies to {@link com.android.server.wm.TaskDisplayArea}. When {@code false}, + * it may rotate based on the orientation request; When {@code true}, it can never specify + * orientation, but shows the fixed-orientation apps in the letterbox. + * @hide + */ + @NonNull + public WindowContainerTransaction setIgnoreOrientationRequest( + @NonNull WindowContainerToken container, boolean ignoreOrientationRequest) { + Change chg = getOrCreateChange(container.asBinder()); + chg.mIgnoreOrientationRequest = ignoreOrientationRequest; + chg.mChangeMask |= Change.CHANGE_IGNORE_ORIENTATION_REQUEST; + return this; + } + + /** * Reparents a container into another one. The effect of a {@code null} parent can vary. For * example, reparenting a stack to {@code null} will reparent it to its display. * @@ -341,10 +357,12 @@ public final class WindowContainerTransaction implements Parcelable { public static final int CHANGE_PIP_CALLBACK = 1 << 2; public static final int CHANGE_HIDDEN = 1 << 3; public static final int CHANGE_BOUNDS_TRANSACTION_RECT = 1 << 4; + public static final int CHANGE_IGNORE_ORIENTATION_REQUEST = 1 << 5; private final Configuration mConfiguration = new Configuration(); private boolean mFocusable = true; private boolean mHidden = false; + private boolean mIgnoreOrientationRequest = false; private int mChangeMask = 0; private @ActivityInfo.Config int mConfigSetMask = 0; private @WindowConfiguration.WindowConfig int mWindowSetMask = 0; @@ -362,6 +380,7 @@ public final class WindowContainerTransaction implements Parcelable { mConfiguration.readFromParcel(in); mFocusable = in.readBoolean(); mHidden = in.readBoolean(); + mIgnoreOrientationRequest = in.readBoolean(); mChangeMask = in.readInt(); mConfigSetMask = in.readInt(); mWindowSetMask = in.readInt(); @@ -404,6 +423,9 @@ public final class WindowContainerTransaction implements Parcelable { if ((other.mChangeMask & CHANGE_HIDDEN) != 0) { mHidden = other.mHidden; } + if ((other.mChangeMask & CHANGE_IGNORE_ORIENTATION_REQUEST) != 0) { + mIgnoreOrientationRequest = other.mIgnoreOrientationRequest; + } mChangeMask |= other.mChangeMask; if (other.mActivityWindowingMode >= 0) { mActivityWindowingMode = other.mActivityWindowingMode; @@ -445,6 +467,15 @@ public final class WindowContainerTransaction implements Parcelable { return mHidden; } + /** Gets the requested state of whether to ignore orientation request. */ + public boolean getIgnoreOrientationRequest() { + if ((mChangeMask & CHANGE_IGNORE_ORIENTATION_REQUEST) == 0) { + throw new RuntimeException("IgnoreOrientationRequest not set. " + + "Check CHANGE_IGNORE_ORIENTATION_REQUEST first"); + } + return mIgnoreOrientationRequest; + } + public int getChangeMask() { return mChangeMask; } @@ -509,6 +540,9 @@ public final class WindowContainerTransaction implements Parcelable { if (mBoundsChangeTransaction != null) { sb.append("hasBoundsTransaction,"); } + if ((mChangeMask & CHANGE_IGNORE_ORIENTATION_REQUEST) != 0) { + sb.append("ignoreOrientationRequest:" + mIgnoreOrientationRequest + ","); + } sb.append("}"); return sb.toString(); } @@ -518,6 +552,7 @@ public final class WindowContainerTransaction implements Parcelable { mConfiguration.writeToParcel(dest, flags); dest.writeBoolean(mFocusable); dest.writeBoolean(mHidden); + dest.writeBoolean(mIgnoreOrientationRequest); dest.writeInt(mChangeMask); dest.writeInt(mConfigSetMask); dest.writeInt(mWindowSetMask); diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index c11624c92117..5239b1f87bea 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -151,6 +151,12 @@ final class TaskDisplayArea extends DisplayArea<Task> { */ private boolean mRemoved; + /** + * Whether the task display area should ignore fixed-orientation request. If {@code true}, it + * can never specify orientation, but show the fixed-orientation apps in the letterbox; + * otherwise, it rotates based on the fixed-orientation request when it has the focus. + */ + private boolean mIgnoreOrientationRequest; /** * The id of a leaf task that most recently being moved to front. @@ -641,11 +647,30 @@ final class TaskDisplayArea extends DisplayArea<Task> { } } + /** + * Sets whether the task display area should ignore fixed-orientation request from apps. + * @return Whether the display orientation changed + */ + boolean setIgnoreOrientationRequest(boolean ignoreOrientationRequest) { + if (mIgnoreOrientationRequest == ignoreOrientationRequest) { + return false; + } + + mIgnoreOrientationRequest = ignoreOrientationRequest; + if (isLastFocused()) { + // Update orientation if this TDA is the last focused, otherwise it shouldn't affect + // the display. + return mDisplayContent.updateOrientation(); + } + + return false; + } + @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()) { + // Only allow to specify orientation if this TDA is not set to ignore orientation request, + // and it has the focus. + if (mIgnoreOrientationRequest || !isLastFocused()) { return SCREEN_ORIENTATION_UNSET; } diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index c7cad2f76486..999181dc486c 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -306,6 +306,19 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub return effects; } + private int applyTaskDisplayAreaChanges(TaskDisplayArea taskDisplayArea, + WindowContainerTransaction.Change c) { + int effects = applyDisplayAreaChanges(taskDisplayArea, c); + if ((c.getChangeMask() + & WindowContainerTransaction.Change.CHANGE_IGNORE_ORIENTATION_REQUEST) != 0) { + if (taskDisplayArea.setIgnoreOrientationRequest(c.getIgnoreOrientationRequest())) { + effects |= TRANSACT_EFFECTS_LIFECYCLE; + } + } + + return effects; + } + private int applyDisplayAreaChanges(WindowContainer container, WindowContainerTransaction.Change c) { final int[] effects = new int[1]; @@ -388,7 +401,9 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub int effects = applyChanges(wc, c); - if (wc instanceof DisplayArea) { + if (wc instanceof TaskDisplayArea) { + effects |= applyTaskDisplayAreaChanges((TaskDisplayArea) wc, c); + } else if (wc instanceof DisplayArea) { effects |= applyDisplayAreaChanges(wc, c); } else if (wc instanceof Task) { effects |= applyTaskChanges(wc.asTask(), c); 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 e71f7ec54b0e..8b025e34401a 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,8 @@ 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.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; @@ -277,6 +279,24 @@ public class TaskDisplayAreaTests extends WindowTestsBase { assertThat(secondTaskDisplayArea.isLastFocused()).isTrue(); } + @Test + public void testIgnoreOrientationRequest() { + final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea(); + final Task stack = taskDisplayArea.createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); + final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true) + .setStack(stack).build(); + + mDisplayContent.setFocusedApp(activity); + activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE); + + assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE); + + taskDisplayArea.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + + assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSET); + } + 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/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java index 11eaf8c5cea5..0152fc607f73 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java @@ -26,6 +26,9 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; 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_LANDSCAPE; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED; import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; @@ -42,6 +45,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; import static com.android.server.wm.DisplayArea.Type.ABOVE_TASKS; import static com.android.server.wm.WindowContainer.POSITION_TOP; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -361,6 +366,45 @@ public class WindowOrganizerTests extends WindowTestsBase { } @Test + public void testSetIgnoreOrientationRequest() { + removeGlobalMinSizeRestriction(); + final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea(); + final Task stack = taskDisplayArea.createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); + final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true) + .setStack(stack).build(); + taskDisplayArea.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mDisplayContent.setFocusedApp(activity); + activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE); + + // TDA returns UNSET when ignoreOrientationRequest == true + // DC is UNSPECIFIED because it is using the previous (default) when TDA returns UNSET. + assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSET); + assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSPECIFIED); + + WindowContainerTransaction t = new WindowContainerTransaction(); + t.setIgnoreOrientationRequest( + taskDisplayArea.mRemoteToken.toWindowContainerToken(), + false /* ignoreOrientationRequest */); + mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); + + // TDA returns app request orientation when ignoreOrientationRequest == false + // DC uses the same as TDA returns when it is not UNSET. + assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE); + assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE); + + t.setIgnoreOrientationRequest( + taskDisplayArea.mRemoteToken.toWindowContainerToken(), + true /* ignoreOrientationRequest */); + mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); + + // TDA returns UNSET when ignoreOrientationRequest == true + // DC is LANDSCAPE because it is using the previous when TDA returns UNSET. + assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSET); + assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE); + } + + @Test public void testOverrideConfigSize() { removeGlobalMinSizeRestriction(); final Task stack = new TaskBuilder(mSupervisor) |