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
This commit is contained in:
Riddle Hsu
2020-07-25 01:44:51 +08:00
parent b511a73d7e
commit 819e1209cd
3 changed files with 43 additions and 20 deletions

View File

@@ -1557,7 +1557,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// the heavy operations. This also benefits that the states of multiple activities // the heavy operations. This also benefits that the states of multiple activities
// are handled together. // are handled together.
r.linkFixedRotationTransform(prevRotatedLaunchingApp); 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; return;
} }

View File

@@ -548,7 +548,7 @@ class WindowToken extends WindowContainer<WindowState> {
void applyFixedRotationTransform(DisplayInfo info, DisplayFrames displayFrames, void applyFixedRotationTransform(DisplayInfo info, DisplayFrames displayFrames,
Configuration config) { Configuration config) {
if (mFixedRotationTransformState != null) { if (mFixedRotationTransformState != null) {
return; cleanUpFixedRotationTransformState(true /* replacing */);
} }
mFixedRotationTransformState = new FixedRotationTransformState(info, displayFrames, mFixedRotationTransformState = new FixedRotationTransformState(info, displayFrames,
new Configuration(config), mDisplayContent.getRotation()); new Configuration(config), mDisplayContent.getRotation());
@@ -565,12 +565,12 @@ class WindowToken extends WindowContainer<WindowState> {
* one. This takes the same effect as {@link #applyFixedRotationTransform}. * one. This takes the same effect as {@link #applyFixedRotationTransform}.
*/ */
void linkFixedRotationTransform(WindowToken other) { void linkFixedRotationTransform(WindowToken other) {
if (mFixedRotationTransformState != null) { final FixedRotationTransformState fixedRotationState = other.mFixedRotationTransformState;
if (fixedRotationState == null || mFixedRotationTransformState == fixedRotationState) {
return; return;
} }
final FixedRotationTransformState fixedRotationState = other.mFixedRotationTransformState; if (mFixedRotationTransformState != null) {
if (fixedRotationState == null) { cleanUpFixedRotationTransformState(true /* replacing */);
return;
} }
mFixedRotationTransformState = fixedRotationState; mFixedRotationTransformState = fixedRotationState;
fixedRotationState.mAssociatedTokens.add(this); fixedRotationState.mAssociatedTokens.add(this);
@@ -626,11 +626,17 @@ class WindowToken extends WindowContainer<WindowState> {
// The state is cleared at the end, because it is used to indicate that other windows can // 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. // use seamless rotation when applying rotation to display.
for (int i = state.mAssociatedTokens.size() - 1; i >= 0; i--) { 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; mFixedRotationTransformState = null;
notifyFixedRotationTransform(false /* enabled */); notifyFixedRotationTransform(false /* enabled */);
} }

View File

@@ -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.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@@ -145,29 +146,40 @@ public class WindowTokenTests extends WindowTestsBase {
assertEquals(0, token.getWindowsCount()); assertEquals(0, token.getWindowsCount());
} }
@UseTestDisplay(addWindows = { W_ACTIVITY, W_WALLPAPER })
@Test @Test
public void testFinishFixedRotationTransform() { public void testFinishFixedRotationTransform() {
final WindowToken appToken = mAppWindow.mToken; final WindowToken[] tokens = new WindowToken[3];
final WindowToken wallpaperToken = mWallpaperWindow.mToken; for (int i = 0; i < tokens.length; i++) {
tokens[i] = createTestWindowToken(TYPE_APPLICATION_OVERLAY, mDisplayContent);
}
final Configuration config = new Configuration(mDisplayContent.getConfiguration()); final Configuration config = new Configuration(mDisplayContent.getConfiguration());
final int originalRotation = config.windowConfiguration.getRotation(); final int originalRotation = config.windowConfiguration.getRotation();
final int targetRotation = (originalRotation + 1) % 4; final int targetRotation = (originalRotation + 1) % 4;
config.windowConfiguration.setRotation(targetRotation); config.windowConfiguration.setRotation(targetRotation);
appToken.applyFixedRotationTransform(mDisplayInfo, mDisplayContent.mDisplayFrames, config); tokens[0].applyFixedRotationTransform(mDisplayInfo, mDisplayContent.mDisplayFrames, config);
wallpaperToken.linkFixedRotationTransform(appToken); tokens[1].linkFixedRotationTransform(tokens[0]);
// The window tokens should apply the rotation by the transformation. // The window tokens should apply the rotation by the transformation.
assertEquals(targetRotation, appToken.getWindowConfiguration().getRotation()); assertEquals(targetRotation, tokens[0].getWindowConfiguration().getRotation());
assertEquals(targetRotation, wallpaperToken.getWindowConfiguration().getRotation()); assertEquals(targetRotation, tokens[1].getWindowConfiguration().getRotation());
// The display doesn't rotate, the transformation will be canceled. tokens[2].applyFixedRotationTransform(mDisplayInfo, mDisplayContent.mDisplayFrames, config);
mAppWindow.mToken.finishFixedRotationTransform(); // 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. // Assume the display doesn't rotate, the transformation will be canceled.
assertEquals(originalRotation, appToken.getWindowConfiguration().getRotation()); tokens[0].finishFixedRotationTransform();
assertEquals(originalRotation, wallpaperToken.getWindowConfiguration().getRotation());
// 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());
} }
/** /**