From f41034c72a8b66bf06a0837ae6a4126a259ebb6e Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Thu, 19 Mar 2020 13:10:46 +0800 Subject: [PATCH] Use task bounds as local animation frame in fixed rotation When switching to a fixed rotation transformed activity, the activity will be rotated but display and task are still in original rotation. So the local animation should use the same coordinate space as display. The insets for animation are not handled because aspect-scaled-thumbnail animation is no longer used (replaced by recents animation). So the methods in rotator are also simplified. Bug: 151709552 Test: DisplayContentTests#testApplyTopFixedRotationTransform Test: Enable fixed_rotation_transform and launch activity with ActivityOptions#makeClipRevealAnimation in different orientation. Change-Id: I7c924719eb535252509305cd842cdb4e0279b858 --- .../com/android/server/wm/ActivityRecord.java | 6 ---- .../android/server/wm/SeamlessRotator.java | 30 ++++--------------- .../com/android/server/wm/WindowState.java | 7 ++++- .../com/android/server/wm/WindowToken.java | 18 +++-------- .../server/wm/DisplayContentTests.java | 9 ++++++ 5 files changed, 24 insertions(+), 46 deletions(-) diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 00c6f3a65d09a..6d53786ddf414 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -7677,12 +7677,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return; } win.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets); - if (isFixedRotationTransforming()) { - // This activity has been rotated but the display is still in old rotation. Because the - // animation applies in display space coordinates, the rotated animation frames need to - // be unrotated to avoid being cropped. - unrotateAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets); - } } void setPictureInPictureParams(PictureInPictureParams p) { diff --git a/services/core/java/com/android/server/wm/SeamlessRotator.java b/services/core/java/com/android/server/wm/SeamlessRotator.java index 8e1c6329f39d9..c79cb04a824f6 100644 --- a/services/core/java/com/android/server/wm/SeamlessRotator.java +++ b/services/core/java/com/android/server/wm/SeamlessRotator.java @@ -20,7 +20,6 @@ import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; import android.graphics.Matrix; -import android.graphics.Rect; import android.os.IBinder; import android.view.DisplayInfo; import android.view.Surface.Rotation; @@ -28,7 +27,6 @@ import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import com.android.server.wm.utils.CoordinateTransforms; -import com.android.server.wm.utils.InsetUtils; import java.io.PrintWriter; import java.io.StringWriter; @@ -47,22 +45,18 @@ public class SeamlessRotator { private final float[] mFloat9 = new float[9]; private final int mOldRotation; private final int mNewRotation; - private final int mRotationDelta; - private final int mW; - private final int mH; public SeamlessRotator(@Rotation int oldRotation, @Rotation int newRotation, DisplayInfo info) { mOldRotation = oldRotation; mNewRotation = newRotation; - mRotationDelta = DisplayContent.deltaRotation(oldRotation, newRotation); final boolean flipped = info.rotation == ROTATION_90 || info.rotation == ROTATION_270; - mH = flipped ? info.logicalWidth : info.logicalHeight; - mW = flipped ? info.logicalHeight : info.logicalWidth; - + final int pH = flipped ? info.logicalWidth : info.logicalHeight; + final int pW = flipped ? info.logicalHeight : info.logicalWidth; + // Initialize transform matrix by physical size. final Matrix tmp = new Matrix(); - CoordinateTransforms.transformLogicalToPhysicalCoordinates(oldRotation, mW, mH, mTransform); - CoordinateTransforms.transformPhysicalToLogicalCoordinates(newRotation, mW, mH, tmp); + CoordinateTransforms.transformLogicalToPhysicalCoordinates(oldRotation, pW, pH, mTransform); + CoordinateTransforms.transformPhysicalToLogicalCoordinates(newRotation, pW, pH, tmp); mTransform.postConcat(tmp); } @@ -78,20 +72,6 @@ public class SeamlessRotator { transaction.setPosition(win.getSurfaceControl(), winSurfacePos[0], winSurfacePos[1]); } - /** Rotates the frame from {@link #mNewRotation} to {@link #mOldRotation}. */ - void unrotateFrame(Rect inOut) { - if (mRotationDelta == ROTATION_90) { - inOut.set(inOut.top, mH - inOut.right, inOut.bottom, mH - inOut.left); - } else if (mRotationDelta == ROTATION_270) { - inOut.set(mW - inOut.bottom, inOut.left, mW - inOut.top, inOut.right); - } - } - - /** Rotates the insets from {@link #mNewRotation} to {@link #mOldRotation}. */ - void unrotateInsets(Rect inOut) { - InsetUtils.rotateInsets(inOut, mRotationDelta); - } - /** * Returns the rotation of the display before it started rotating. * diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 36175705b8486..161152ba0d747 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -5656,7 +5656,12 @@ class WindowState extends WindowContainer implements WindowManagerP // the status bar). In that case we need to use the final frame. if (inFreeformWindowingMode()) { outFrame.set(getFrameLw()); - } else if (isLetterboxedAppWindow()) { + } else if (isLetterboxedAppWindow() || mToken.isFixedRotationTransforming()) { + // 1. The letterbox surfaces should be animated with the owner activity, so use task + // bounds to include them. + // 2. If the activity has fixed rotation transform, its windows are rotated in activity + // level. Because the animation runs before display is rotated, task bounds should + // represent the frames in display space coordinates. outFrame.set(getTask().getBounds()); } else if (isDockedResizing()) { // If we are animating while docked resizing, then use the stack bounds as the diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index b7c6af2f7a0de..f965f7b80ee94 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -154,7 +154,10 @@ class WindowToken extends WindowContainer { void resetTransform() { for (int i = mRotatedContainers.size() - 1; i >= 0; i--) { final WindowContainer c = mRotatedContainers.get(i); - mRotator.finish(c.getPendingTransaction(), c); + // If the window is detached (no parent), its surface may have been released. + if (c.getParent() != null) { + mRotator.finish(c.getPendingTransaction(), c); + } } } } @@ -509,19 +512,6 @@ class WindowToken extends WindowContainer { } } - /** - * Converts the rotated animation frames and insets back to display space for local animation. - * It should only be called when {@link #hasFixedRotationTransform} is true. - */ - void unrotateAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets, - Rect outSurfaceInsets) { - final SeamlessRotator rotator = mFixedRotationTransformState.mRotator; - rotator.unrotateFrame(outFrame); - rotator.unrotateInsets(outInsets); - rotator.unrotateInsets(outStableInsets); - rotator.unrotateInsets(outSurfaceInsets); - } - /** * Gives a chance to this {@link WindowToken} to adjust the {@link * android.view.WindowManager.LayoutParams} of its windows. diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index b3c6b22bf265c..218c8169e7e60 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -1016,6 +1016,15 @@ public class DisplayContentTests extends WindowTestsBase { assertTrue(mDisplayContent.getDisplayRotation().shouldRotateSeamlessly( ROTATION_0 /* oldRotation */, ROTATION_90 /* newRotation */, false /* forceUpdate */)); + + final Rect outFrame = new Rect(); + final Rect outInsets = new Rect(); + final Rect outStableInsets = new Rect(); + final Rect outSurfaceInsets = new Rect(); + mAppWindow.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets); + // The animation frames should not be rotated because display hasn't rotated. + assertEquals(mDisplayContent.getBounds(), outFrame); + // The display should keep current orientation and the rotated configuration should apply // to the activity. assertEquals(config.orientation, mDisplayContent.getConfiguration().orientation);