Handle orientation behind for fixed rotation

The activity which decides the display orientation may not always
be the top activity, such as declaring "behind" orientation. And
because recents animation will be canceled when display orientation
changes, it causes to fail swiping to a orientation-behind app.

So simply get the real top if the orientation source is not visible.

Bug: 226298709
Test: atest DisplayContentTests#testOrientationBehind
Test: With TaskA{portrait}, TaskB{behind, landscape}, it should
      be able to use quickstep to swipe from TaskA to TaskB

Change-Id: I4cf9f3ab977ac7c8b22eb4c37218a5d2019bfabc
This commit is contained in:
Riddle Hsu
2022-04-15 14:31:30 +08:00
parent 8116d48598
commit 677f71a853
2 changed files with 45 additions and 8 deletions

View File

@@ -1575,8 +1575,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mAtmService.getTaskChangeNotificationController()
.notifyTaskRequestedOrientationChanged(task.mTaskId, orientation);
}
// Currently there is no use case from non-activity.
if (handleTopActivityLaunchingInDifferentOrientation(r, true /* checkOpening */)) {
// The orientation source may not be the top if it uses SCREEN_ORIENTATION_BEHIND.
final ActivityRecord topCandidate = !r.mVisibleRequested ? topRunningActivity() : r;
if (handleTopActivityLaunchingInDifferentOrientation(
topCandidate, r, true /* checkOpening */)) {
// Display orientation should be deferred until the top fixed rotation is finished.
return false;
}
@@ -1593,7 +1595,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
/**
* Returns a valid rotation if the activity can use different orientation than the display.
* Otherwise {@link #ROTATION_UNDEFINED}.
* Otherwise {@link android.app.WindowConfiguration#ROTATION_UNDEFINED}.
*/
@Rotation
int rotationForActivityInDifferentOrientation(@NonNull ActivityRecord r) {
@@ -1603,6 +1605,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
if (!WindowManagerService.ENABLE_FIXED_ROTATION_TRANSFORM) {
return ROTATION_UNDEFINED;
}
if (r.mOrientation == ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
final ActivityRecord nextCandidate = getActivity(
a -> a.mOrientation != SCREEN_ORIENTATION_UNSET
&& a.mOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND,
r, false /* includeBoundary */, true /* traverseTopToBottom */);
if (nextCandidate != null) {
r = nextCandidate;
}
}
if (r.inMultiWindowMode() || r.getRequestedConfigurationOrientation(true /* forDisplay */)
== getConfiguration().orientation) {
return ROTATION_UNDEFINED;
@@ -1616,18 +1627,25 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
return rotation;
}
boolean handleTopActivityLaunchingInDifferentOrientation(@NonNull ActivityRecord r,
boolean checkOpening) {
return handleTopActivityLaunchingInDifferentOrientation(r, r, checkOpening);
}
/**
* We need to keep display rotation fixed for a while when the activity in different orientation
* is launching until the launch animation is done to avoid showing the previous activity
* inadvertently in a wrong orientation.
*
* @param r The launching activity which may change display orientation.
* @param orientationSrc It may be different from {@param r} if the launching activity uses
* "behind" orientation.
* @param checkOpening Whether to check if the activity is animating by transition. Set to
* {@code true} if the caller is not sure whether the activity is launching.
* @return {@code true} if the fixed rotation is started.
*/
boolean handleTopActivityLaunchingInDifferentOrientation(@NonNull ActivityRecord r,
boolean checkOpening) {
private boolean handleTopActivityLaunchingInDifferentOrientation(@NonNull ActivityRecord r,
@NonNull ActivityRecord orientationSrc, boolean checkOpening) {
if (!WindowManagerService.ENABLE_FIXED_ROTATION_TRANSFORM) {
return false;
}
@@ -1676,7 +1694,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// animation is not running (it may be swiping to home).
return false;
}
final int rotation = rotationForActivityInDifferentOrientation(r);
final int rotation = rotationForActivityInDifferentOrientation(orientationSrc);
if (rotation == ROTATION_UNDEFINED) {
// The display rotation won't be changed by current top activity. The client side
// adjustments of previous rotated activity should be cleared earlier. Otherwise if

View File

@@ -22,6 +22,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -1092,6 +1093,25 @@ public class DisplayContentTests extends WindowTestsBase {
assertEquals(ROTATION_180, dc.getRotation());
}
@Test
public void testOrientationBehind() {
final ActivityRecord prev = new ActivityBuilder(mAtm).setCreateTask(true)
.setScreenOrientation(getRotatedOrientation(mDisplayContent)).build();
prev.mVisibleRequested = false;
final ActivityRecord top = new ActivityBuilder(mAtm).setCreateTask(true)
.setScreenOrientation(SCREEN_ORIENTATION_BEHIND).build();
assertNotEquals(WindowConfiguration.ROTATION_UNDEFINED,
mDisplayContent.rotationForActivityInDifferentOrientation(top));
mDisplayContent.requestTransitionAndLegacyPrepare(WindowManager.TRANSIT_OPEN, 0);
top.setVisibility(true);
mDisplayContent.updateOrientation();
// The top uses "behind", so the orientation is decided by the previous.
assertEquals(prev, mDisplayContent.getLastOrientationSource());
// The top will use the rotation from "prev" with fixed rotation.
assertTrue(top.hasFixedRotationTransform());
}
@Test
public void testFixedToUserRotationChanged() {
final DisplayContent dc = createNewDisplay();
@@ -1650,8 +1670,7 @@ public class DisplayContentTests extends WindowTestsBase {
// The condition should reject using fixed rotation because the resumed client in real case
// might get display info immediately. And the fixed rotation adjustments haven't arrived
// client side so the info may be inconsistent with the requested orientation.
verify(mDisplayContent).handleTopActivityLaunchingInDifferentOrientation(eq(app),
eq(true) /* checkOpening */);
verify(mDisplayContent).updateOrientation(eq(app), anyBoolean());
assertFalse(app.isFixedRotationTransforming());
assertFalse(mDisplayContent.hasTopFixedRotationLaunchingApp());
}