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
This commit is contained in:
Chris Li
2020-09-14 12:45:11 -07:00
parent f747948b6d
commit 3dbefb99c4
5 changed files with 143 additions and 4 deletions

View File

@@ -237,6 +237,22 @@ public final class WindowContainerTransaction implements Parcelable {
return this;
}
/**
* 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);

View File

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

View File

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

View File

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

View File

@@ -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;
@@ -360,6 +365,45 @@ public class WindowOrganizerTests extends WindowTestsBase {
assertTrue(stack.shouldBeVisible(null));
}
@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();