Loading services/core/java/com/android/server/wm/DisplayContent.java +24 −6 Original line number Diff line number Diff line Loading @@ -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; } Loading @@ -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) { Loading @@ -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; Loading @@ -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; } Loading Loading @@ -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 Loading services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +21 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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()); } Loading Loading
services/core/java/com/android/server/wm/DisplayContent.java +24 −6 Original line number Diff line number Diff line Loading @@ -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; } Loading @@ -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) { Loading @@ -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; Loading @@ -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; } Loading Loading @@ -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 Loading
services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +21 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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()); } Loading