From 819e1209cdd873a4eb7402417a1cabd9e0039f6c Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Sat, 25 Jul 2020 01:44:51 +0800 Subject: [PATCH] Allow to replace fixed rotation state Assume there are 2 activities with different fixed rotation states A and B. And wallpaper was associated with A. When the wallpaper target is changed to B, wallpaper should be able to change the association to B so their rotation transform can be updated at the same time. This also avoids that if the previous associated token is somehow inactive, wallpaper won't in a dangling rotated state. Also add a check of updating rotated launching app for the case: launching a portrait app from a landscape app and trigger recents animation immediately before the animation of portrait app is done. And then finish recents animation by keeping the portrait app as the top activity. The expected result should be that the display is rotated from landscape to portrait seamlessly. But if the recents activity is set to the rotated launching app, the display rotation will be unable to update because when receiving animation done of the portrait app, the recents animation is still active that skips the rotation change. Then the portrait app will be updated to landscape temporally. Fixes: 161056612 Test: atest WindowTokenTests#testFinishFixedRotationTransform Change-Id: Ic134c4326db836e35385f290f996f0d841da693d --- .../com/android/server/wm/DisplayContent.java | 7 +++- .../com/android/server/wm/WindowToken.java | 20 +++++++---- .../android/server/wm/WindowTokenTests.java | 36 ++++++++++++------- 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index fc170538994c5..02e112ee9b7dc 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -1557,7 +1557,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // the heavy operations. This also benefits that the states of multiple activities // are handled together. r.linkFixedRotationTransform(prevRotatedLaunchingApp); - setFixedRotationLaunchingAppUnchecked(r, rotation); + if (r != mFixedRotationTransitionListener.mAnimatingRecents) { + // Only update the record for normal activity so the display orientation can be + // updated when the transition is done if it becomes the top. And the case of + // recents can be handled when the recents animation is finished. + setFixedRotationLaunchingAppUnchecked(r, rotation); + } return; } diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index 2c1bb3ec51ebf..6d3ae304f62a8 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -548,7 +548,7 @@ class WindowToken extends WindowContainer { void applyFixedRotationTransform(DisplayInfo info, DisplayFrames displayFrames, Configuration config) { if (mFixedRotationTransformState != null) { - return; + cleanUpFixedRotationTransformState(true /* replacing */); } mFixedRotationTransformState = new FixedRotationTransformState(info, displayFrames, new Configuration(config), mDisplayContent.getRotation()); @@ -565,12 +565,12 @@ class WindowToken extends WindowContainer { * one. This takes the same effect as {@link #applyFixedRotationTransform}. */ void linkFixedRotationTransform(WindowToken other) { - if (mFixedRotationTransformState != null) { + final FixedRotationTransformState fixedRotationState = other.mFixedRotationTransformState; + if (fixedRotationState == null || mFixedRotationTransformState == fixedRotationState) { return; } - final FixedRotationTransformState fixedRotationState = other.mFixedRotationTransformState; - if (fixedRotationState == null) { - return; + if (mFixedRotationTransformState != null) { + cleanUpFixedRotationTransformState(true /* replacing */); } mFixedRotationTransformState = fixedRotationState; fixedRotationState.mAssociatedTokens.add(this); @@ -626,11 +626,17 @@ class WindowToken extends WindowContainer { // The state is cleared at the end, because it is used to indicate that other windows can // use seamless rotation when applying rotation to display. for (int i = state.mAssociatedTokens.size() - 1; i >= 0; i--) { - state.mAssociatedTokens.get(i).cleanUpFixedRotationTransformState(); + state.mAssociatedTokens.get(i).cleanUpFixedRotationTransformState( + false /* replacing */); } } - private void cleanUpFixedRotationTransformState() { + private void cleanUpFixedRotationTransformState(boolean replacing) { + if (replacing && mFixedRotationTransformState.mAssociatedTokens.size() > 1) { + // The state is not only used by self. Make sure to leave the influence by others. + mFixedRotationTransformState.mAssociatedTokens.remove(this); + mFixedRotationTransformState.mRotatedContainers.remove(this); + } mFixedRotationTransformState = null; notifyFixedRotationTransform(false /* enabled */); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java index d9c48fc4ba374..e0785c13a336b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java @@ -27,6 +27,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -145,29 +146,40 @@ public class WindowTokenTests extends WindowTestsBase { assertEquals(0, token.getWindowsCount()); } - @UseTestDisplay(addWindows = { W_ACTIVITY, W_WALLPAPER }) @Test public void testFinishFixedRotationTransform() { - final WindowToken appToken = mAppWindow.mToken; - final WindowToken wallpaperToken = mWallpaperWindow.mToken; + final WindowToken[] tokens = new WindowToken[3]; + for (int i = 0; i < tokens.length; i++) { + tokens[i] = createTestWindowToken(TYPE_APPLICATION_OVERLAY, mDisplayContent); + } + final Configuration config = new Configuration(mDisplayContent.getConfiguration()); final int originalRotation = config.windowConfiguration.getRotation(); final int targetRotation = (originalRotation + 1) % 4; config.windowConfiguration.setRotation(targetRotation); - appToken.applyFixedRotationTransform(mDisplayInfo, mDisplayContent.mDisplayFrames, config); - wallpaperToken.linkFixedRotationTransform(appToken); + tokens[0].applyFixedRotationTransform(mDisplayInfo, mDisplayContent.mDisplayFrames, config); + tokens[1].linkFixedRotationTransform(tokens[0]); // The window tokens should apply the rotation by the transformation. - assertEquals(targetRotation, appToken.getWindowConfiguration().getRotation()); - assertEquals(targetRotation, wallpaperToken.getWindowConfiguration().getRotation()); + assertEquals(targetRotation, tokens[0].getWindowConfiguration().getRotation()); + assertEquals(targetRotation, tokens[1].getWindowConfiguration().getRotation()); - // The display doesn't rotate, the transformation will be canceled. - mAppWindow.mToken.finishFixedRotationTransform(); + tokens[2].applyFixedRotationTransform(mDisplayInfo, mDisplayContent.mDisplayFrames, config); + // The tokens[1] was linked to tokens[0], this should make tokens[1] link to tokens[2]. + tokens[1].linkFixedRotationTransform(tokens[2]); - // The window tokens should restore to the original rotation. - assertEquals(originalRotation, appToken.getWindowConfiguration().getRotation()); - assertEquals(originalRotation, wallpaperToken.getWindowConfiguration().getRotation()); + // Assume the display doesn't rotate, the transformation will be canceled. + tokens[0].finishFixedRotationTransform(); + + // The tokens[0] should restore to the original rotation. + assertEquals(originalRotation, tokens[0].getWindowConfiguration().getRotation()); + // The tokens[1] is linked to tokens[2], it should keep the target rotation. + assertNotEquals(originalRotation, tokens[1].getWindowConfiguration().getRotation()); + + tokens[2].finishFixedRotationTransform(); + // The rotation of tokens[1] should be restored because its linked state is finished. + assertEquals(originalRotation, tokens[1].getWindowConfiguration().getRotation()); } /**