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:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user