Merge "Support ignoring orientation request on DisplayArea level"

This commit is contained in:
Wale Ogunwale
2020-10-14 13:58:32 +00:00
committed by Android (Google) Code Review
9 changed files with 203 additions and 78 deletions

View File

@@ -238,10 +238,10 @@ 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.
* Sets whether a container should ignore the orientation request from apps and windows below
* it. It currently only applies to {@link com.android.server.wm.DisplayArea}. 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 below it in the letterbox.
* @hide
*/
@NonNull

View File

@@ -301,12 +301,6 @@
"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",
@@ -529,6 +523,12 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/Task.java"
},
"-1480772131": {
"message": "No app or window is requesting an orientation, return %d for display id=%d",
"level": "VERBOSE",
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
"-1474292612": {
"message": "Could not find task for id: %d",
"level": "DEBUG",
@@ -2515,12 +2515,6 @@
"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"
},
"849147756": {
"message": "Finish collecting in transition %d",
"level": "VERBOSE",
@@ -2923,6 +2917,12 @@
"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",
@@ -3133,6 +3133,18 @@
"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"
},
"1648338379": {
"message": "Display id=%d is ignoring all orientation requests, return %d",
"level": "VERBOSE",
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
"1653210583": {
"message": "Removing app %s delayed=%b animation=%s animating=%b",
"level": "VERBOSE",

View File

@@ -41,6 +41,7 @@ import android.window.IDisplayAreaOrganizer;
import com.android.internal.protolog.common.ProtoLog;
import com.android.server.policy.WindowManagerPolicy;
import java.io.PrintWriter;
import java.util.Comparator;
import java.util.function.BiFunction;
import java.util.function.Consumer;
@@ -71,6 +72,13 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
IDisplayAreaOrganizer mOrganizer;
private final Configuration mTmpConfiguration = new Configuration();
/**
* Whether this {@link DisplayArea} should ignore fixed-orientation request. If {@code true}, it
* can never specify orientation, but shows the fixed-orientation apps below it in the
* letterbox; otherwise, it rotates based on the fixed-orientation request.
*/
protected boolean mIgnoreOrientationRequest;
DisplayArea(WindowManagerService wms, Type type, String name) {
this(wms, type, name, FEATURE_UNDEFINED);
}
@@ -127,6 +135,52 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
}
}
@Override
int getOrientation(int candidate) {
mLastOrientationSource = null;
if (mIgnoreOrientationRequest) {
return SCREEN_ORIENTATION_UNSET;
}
return super.getOrientation(candidate);
}
/**
* Sets whether this {@link DisplayArea} should ignore fixed-orientation request from apps and
* windows below it.
*
* @return Whether the display orientation changed after calling this method.
*/
boolean setIgnoreOrientationRequest(boolean ignoreOrientationRequest) {
if (mIgnoreOrientationRequest == ignoreOrientationRequest) {
return false;
}
mIgnoreOrientationRequest = ignoreOrientationRequest;
// Check whether we should notify Display to update orientation.
if (mDisplayContent == null) {
return false;
}
// The orientation request from this DA may now be respected.
if (!ignoreOrientationRequest) {
return mDisplayContent.updateOrientation();
}
final int lastOrientation = mDisplayContent.getLastOrientation();
final WindowContainer lastOrientationSource = mDisplayContent.getLastOrientationSource();
if (lastOrientation == SCREEN_ORIENTATION_UNSET
|| lastOrientation == SCREEN_ORIENTATION_UNSPECIFIED) {
// Orientation won't be changed.
return false;
}
if (lastOrientationSource == null || lastOrientationSource.isDescendantOf(this)) {
// Try update if the orientation may be affected.
return mDisplayContent.updateOrientation();
}
return false;
}
/**
* When a {@link DisplayArea} is repositioned, it should only be moved among its siblings of the
* same {@link Type}.
@@ -199,6 +253,14 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
proto.end(token);
}
@Override
void dump(PrintWriter pw, String prefix, boolean dumpAll) {
super.dump(pw, prefix, dumpAll);
if (mIgnoreOrientationRequest) {
pw.println(prefix + "mIgnoreOrientationRequest=true");
}
}
@Override
long getProtoFieldId() {
return DISPLAY_AREA;
@@ -409,6 +471,10 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
@Override
int getOrientation(int candidate) {
mLastOrientationSource = null;
if (mIgnoreOrientationRequest) {
return SCREEN_ORIENTATION_UNSET;
}
// Find a window requesting orientation.
final WindowState win = getWindow(mGetOrientingWindow);

View File

@@ -28,8 +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.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
@@ -2347,6 +2347,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
@Override
int getOrientation() {
mLastOrientationSource = null;
if (mIgnoreOrientationRequest) {
// Return SCREEN_ORIENTATION_UNSPECIFIED so that Display respect sensor rotation
ProtoLog.v(WM_DEBUG_ORIENTATION,
"Display id=%d is ignoring all orientation requests, return %d",
mDisplayId, SCREEN_ORIENTATION_UNSPECIFIED);
return SCREEN_ORIENTATION_UNSPECIFIED;
}
if (mWmService.mDisplayFrozen) {
if (mWmService.mPolicy.isKeyguardLocked()) {
@@ -2363,19 +2370,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
final int orientation = super.getOrientation();
if (orientation != SCREEN_ORIENTATION_UNSET && orientation != SCREEN_ORIENTATION_BEHIND) {
if (orientation == SCREEN_ORIENTATION_UNSET) {
// Return SCREEN_ORIENTATION_UNSPECIFIED so that Display respect sensor rotation
ProtoLog.v(WM_DEBUG_ORIENTATION,
"App is requesting an orientation, return %d for display id=%d",
orientation, mDisplayId);
return orientation;
"No app or window is requesting an orientation, return %d for display id=%d",
SCREEN_ORIENTATION_UNSPECIFIED, mDisplayId);
return SCREEN_ORIENTATION_UNSPECIFIED;
}
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();
return orientation;
}
void updateDisplayInfo() {
@@ -4243,6 +4246,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
@Override
int getOrientation(int candidate) {
if (mIgnoreOrientationRequest) {
return SCREEN_ORIENTATION_UNSET;
}
// IME does not participate in orientation.
return candidate;
}

View File

@@ -29,10 +29,12 @@ 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.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
import static com.android.server.wm.ActivityTaskManagerService.TAG_STACK;
@@ -149,13 +151,6 @@ 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.
*/
@@ -654,28 +649,9 @@ 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) {
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()) {
@@ -708,7 +684,21 @@ final class TaskDisplayArea extends DisplayArea<Task> {
return SCREEN_ORIENTATION_UNSPECIFIED;
}
return super.getOrientation(candidate);
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();
}
@Override

View File

@@ -380,24 +380,18 @@ 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,
private int applyDisplayAreaChanges(DisplayArea displayArea,
WindowContainerTransaction.Change c) {
final int[] effects = new int[1];
container.forAllTasks(task -> {
if ((c.getChangeMask()
& WindowContainerTransaction.Change.CHANGE_IGNORE_ORIENTATION_REQUEST) != 0) {
if (displayArea.setIgnoreOrientationRequest(c.getIgnoreOrientationRequest())) {
effects[0] |= TRANSACT_EFFECTS_LIFECYCLE;
}
}
displayArea.forAllTasks(task -> {
Task tr = (Task) task;
if ((c.getChangeMask() & WindowContainerTransaction.Change.CHANGE_HIDDEN) != 0) {
if (tr.setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, c.getHidden())) {
@@ -475,10 +469,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
int effects = applyChanges(wc, c);
if (wc instanceof TaskDisplayArea) {
effects |= applyTaskDisplayAreaChanges((TaskDisplayArea) wc, c);
} else if (wc instanceof DisplayArea) {
effects |= applyDisplayAreaChanges(wc, c);
if (wc instanceof DisplayArea) {
effects |= applyDisplayAreaChanges(wc.asDisplayArea(), c);
} else if (wc instanceof Task) {
effects |= applyTaskChanges(wc.asTask(), c);
}

View File

@@ -438,6 +438,28 @@ public class DisplayAreaTest {
area.getOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR));
}
@Test
public void testSetIgnoreOrientationRequest() {
final DisplayArea.Tokens area = new DisplayArea.Tokens(mWms, ABOVE_TASKS, "test");
final WindowToken token = createWindowToken(TYPE_APPLICATION_OVERLAY);
spyOn(token);
doReturn(mock(DisplayContent.class)).when(token).getDisplayContent();
doNothing().when(token).setParent(any());
final WindowState win = createWindowState(token);
spyOn(win);
doNothing().when(win).setParent(any());
win.mAttrs.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
token.addChild(win, 0);
area.addChild(token);
doReturn(true).when(win).isVisible();
assertEquals(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, area.getOrientation());
area.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
assertEquals(ActivityInfo.SCREEN_ORIENTATION_UNSET, area.getOrientation());
}
private static class TestDisplayArea<T extends WindowContainer> extends DisplayArea<T> {
private TestDisplayArea(WindowManagerService wms, Rect bounds) {
super(wms, ANY, "half display area");

View File

@@ -1002,14 +1002,18 @@ public class TaskRecordTests extends WindowTestsBase {
public void testNotSpecifyOrientationByFloatingTask() {
final Task task = getTestTask();
final ActivityRecord activity = task.getTopMostActivity();
final WindowContainer<?> parentContainer = task.getParent();
final TaskDisplayArea taskDisplayArea = task.getDisplayArea();
activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
assertEquals(SCREEN_ORIENTATION_LANDSCAPE, parentContainer.getOrientation());
assertEquals(SCREEN_ORIENTATION_LANDSCAPE, taskDisplayArea.getOrientation());
task.setWindowingMode(WINDOWING_MODE_PINNED);
assertEquals(SCREEN_ORIENTATION_UNSET, taskDisplayArea.getOrientation());
// TDA returns the last orientation when child returns UNSET
assertEquals(SCREEN_ORIENTATION_UNSET, parentContainer.getOrientation());
assertEquals(SCREEN_ORIENTATION_LANDSCAPE, taskDisplayArea.getOrientation());
}
@Test

View File

@@ -366,7 +366,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
}
@Test
public void testSetIgnoreOrientationRequest() {
public void testSetIgnoreOrientationRequest_taskDisplayArea() {
removeGlobalMinSizeRestriction();
final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
final Task stack = taskDisplayArea.createStack(
@@ -378,7 +378,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
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.
// DC is UNSPECIFIED when child returns UNSET
assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSET);
assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSPECIFIED);
@@ -399,8 +399,40 @@ public class WindowOrganizerTests extends WindowTestsBase {
mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
// TDA returns UNSET when ignoreOrientationRequest == true
// DC is LANDSCAPE because it is using the previous when TDA returns UNSET.
// DC is UNSPECIFIED when child returns UNSET
assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSET);
assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSPECIFIED);
}
@Test
public void testSetIgnoreOrientationRequest_displayContent() {
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();
mDisplayContent.setFocusedApp(activity);
activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
// DC uses the orientation request from app
assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE);
WindowContainerTransaction t = new WindowContainerTransaction();
t.setIgnoreOrientationRequest(
mDisplayContent.mRemoteToken.toWindowContainerToken(),
true /* ignoreOrientationRequest */);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
// DC returns UNSPECIFIED when ignoreOrientationRequest == true
assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSPECIFIED);
t.setIgnoreOrientationRequest(
mDisplayContent.mRemoteToken.toWindowContainerToken(),
false /* ignoreOrientationRequest */);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
// DC uses the orientation request from app after mIgnoreOrientationRequest is set to false
assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE);
}