Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 841beb63 authored by Tony Huang's avatar Tony Huang
Browse files

Implement crossfade and jumpcut rotation

Implement crossfade and jumpcut rotation animation into shell
transition.

Bug: 194715257
Test: manual
Test: pass existing tests
Change-Id: I12269971b22614ce16fb3329b52fc7bdef25af05
parent d448dc23
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -313,7 +313,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
                    final int anim = getRotationAnimation(info);
                    if (!(isSeamless || anim == ROTATION_ANIMATION_JUMPCUT)) {
                        mRotationAnimation = new ScreenRotationAnimation(mContext, mSurfaceSession,
                                mTransactionPool, startTransaction, change, info.getRootLeash());
                                mTransactionPool, startTransaction, change, info.getRootLeash(),
                                anim);
                        mRotationAnimation.startAnimation(animations, onAnimFinish,
                                mTransitionAnimationScaleSetting, mMainExecutor, mAnimExecutor);
                        continue;
+93 −57
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.wm.shell.transition;
import static android.hardware.HardwareBuffer.RGBA_8888;
import static android.hardware.HardwareBuffer.USAGE_PROTECTED_CONTENT;
import static android.util.RotationUtils.deltaRotation;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT;
import static android.view.WindowManagerPolicyConstants.SCREEN_FREEZE_LAYER_BASE;

import static com.android.wm.shell.transition.DefaultTransitionHandler.startSurfaceAnimation;
@@ -59,7 +61,7 @@ import java.util.Arrays;
 * This class handles the rotation animation when the device is rotated.
 *
 * <p>
 * The screen rotation animation is composed of 4 different part:
 * The screen rotation animation is composed of 3 different part:
 * <ul>
 * <li> The screenshot: <p>
 *     A screenshot of the whole screen prior the change of orientation is taken to hide the
@@ -75,10 +77,6 @@ import java.util.Arrays;
 *      To have the animation seem more seamless, we add a color transitioning background behind the
 *      exiting and entering layouts. We compute the brightness of the start and end
 *      layouts and transition from the two brightness values as grayscale underneath the animation
 *
 * <li> The entering Blackframe: <p>
 *     The enter Blackframe is similar to the exit Blackframe but is only used when a custom
 *     rotation animation is used and matches the new content size instead of the screenshot.
 * </ul>
 */
class ScreenRotationAnimation {
@@ -94,6 +92,7 @@ class ScreenRotationAnimation {
    private final Rect mStartBounds = new Rect();
    private final Rect mEndBounds = new Rect();

    private final int mAnimHint;
    private final int mStartWidth;
    private final int mStartHeight;
    private final int mEndWidth;
@@ -117,6 +116,7 @@ class ScreenRotationAnimation {
    // rotations.
    private Animation mRotateExitAnimation;
    private Animation mRotateEnterAnimation;
    private Animation mRotateAlphaAnimation;

    /** Intensity of light/whiteness of the layout before rotation occurs. */
    private float mStartLuma;
@@ -124,9 +124,10 @@ class ScreenRotationAnimation {
    private float mEndLuma;

    ScreenRotationAnimation(Context context, SurfaceSession session, TransactionPool pool,
            Transaction t, TransitionInfo.Change change, SurfaceControl rootLeash) {
            Transaction t, TransitionInfo.Change change, SurfaceControl rootLeash, int animHint) {
        mContext = context;
        mTransactionPool = pool;
        mAnimHint = animHint;

        mSurfaceControl = change.getLeash();
        mStartWidth = change.getStartAbsBounds().width();
@@ -160,13 +161,6 @@ class ScreenRotationAnimation {
                return;
            }

            mBackColorSurface = new SurfaceControl.Builder(session)
                    .setParent(rootLeash)
                    .setColorLayer()
                    .setCallsite("ShellRotationAnimation")
                    .setName("BackColorSurface")
                    .build();

            mScreenshotLayer = new SurfaceControl.Builder(session)
                    .setParent(mAnimLeash)
                    .setBLASTLayer()
@@ -175,17 +169,9 @@ class ScreenRotationAnimation {
                    .setName("RotationLayer")
                    .build();

            HardwareBuffer hardwareBuffer = screenshotBuffer.getHardwareBuffer();
            mStartLuma = getMedianBorderLuma(hardwareBuffer, screenshotBuffer.getColorSpace());

            GraphicBuffer buffer = GraphicBuffer.createFromHardwareBuffer(
                    screenshotBuffer.getHardwareBuffer());

            t.setLayer(mBackColorSurface, -1);
            t.setColor(mBackColorSurface, new float[]{mStartLuma, mStartLuma, mStartLuma});
            t.setAlpha(mBackColorSurface, 1);
            t.show(mBackColorSurface);

            t.setLayer(mAnimLeash, SCREEN_FREEZE_LAYER_BASE);
            t.setPosition(mAnimLeash, 0, 0);
            t.setAlpha(mAnimLeash, 1);
@@ -195,6 +181,23 @@ class ScreenRotationAnimation {
            t.setColorSpace(mScreenshotLayer, screenshotBuffer.getColorSpace());
            t.show(mScreenshotLayer);

            if (!isCustomRotate()) {
                mBackColorSurface = new SurfaceControl.Builder(session)
                        .setParent(rootLeash)
                        .setColorLayer()
                        .setCallsite("ShellRotationAnimation")
                        .setName("BackColorSurface")
                        .build();

                HardwareBuffer hardwareBuffer = screenshotBuffer.getHardwareBuffer();
                mStartLuma = getMedianBorderLuma(hardwareBuffer, screenshotBuffer.getColorSpace());

                t.setLayer(mBackColorSurface, -1);
                t.setColor(mBackColorSurface, new float[]{mStartLuma, mStartLuma, mStartLuma});
                t.setAlpha(mBackColorSurface, 1);
                t.show(mBackColorSurface);
            }

        } catch (Surface.OutOfResourcesException e) {
            Slog.w(TAG, "Unable to allocate freeze surface", e);
        }
@@ -203,6 +206,10 @@ class ScreenRotationAnimation {
        t.apply();
    }

    private boolean isCustomRotate() {
        return mAnimHint == ROTATION_ANIMATION_CROSSFADE || mAnimHint == ROTATION_ANIMATION_JUMPCUT;
    }

    private void setRotation(SurfaceControl.Transaction t) {
        // Compute the transformation matrix that must be applied
        // to the snapshot to make it stay in the same original position
@@ -244,6 +251,16 @@ class ScreenRotationAnimation {
        // color frame animation.
        //mEndLuma = getLumaOfSurfaceControl(mEndBounds, mSurfaceControl);

        final boolean customRotate = isCustomRotate();
        if (customRotate) {
            mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
                    mAnimHint == ROTATION_ANIMATION_JUMPCUT ? R.anim.rotation_animation_jump_exit
                            : R.anim.rotation_animation_xfade_exit);
            mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
                    R.anim.rotation_animation_enter);
            mRotateAlphaAnimation = AnimationUtils.loadAnimation(mContext,
                    R.anim.screen_rotate_alpha);
        } else {
            // Figure out how the screen has moved from the original rotation.
            int delta = deltaRotation(mEndRotation, mStartRotation);
            switch (delta) { /* Counter-Clockwise Rotations */
@@ -272,6 +289,7 @@ class ScreenRotationAnimation {
                            R.anim.screen_rotate_minus_90_enter);
                    break;
            }
        }

        mRotateExitAnimation.initialize(mEndWidth, mEndHeight, mStartWidth, mStartHeight);
        mRotateExitAnimation.restrictDuration(MAX_ANIMATION_DURATION);
@@ -281,9 +299,20 @@ class ScreenRotationAnimation {
        mRotateEnterAnimation.scaleCurrentDuration(animationScale);

        mTransaction = mTransactionPool.acquire();
        if (customRotate) {
            mRotateAlphaAnimation.initialize(mEndWidth, mEndHeight, mStartWidth, mStartHeight);
            mRotateAlphaAnimation.restrictDuration(MAX_ANIMATION_DURATION);
            mRotateAlphaAnimation.scaleCurrentDuration(animationScale);

            startScreenshotAlphaAnimation(animations, finishCallback, mainExecutor,
                    animExecutor);
            startDisplayRotation(animations, finishCallback, mainExecutor, animExecutor);
        } else {
            startDisplayRotation(animations, finishCallback, mainExecutor, animExecutor);
        startScreenshotRotationAnimation(animations, finishCallback, mainExecutor, animExecutor);
            startScreenshotRotationAnimation(animations, finishCallback, mainExecutor,
                    animExecutor);
            //startColorAnimation(mTransaction, animationScale);
        }

        return true;
    }
@@ -304,6 +333,14 @@ class ScreenRotationAnimation {
                0 /* cornerRadius */, null /* clipRect */);
    }

    private void startScreenshotAlphaAnimation(@NonNull ArrayList<Animator> animations,
            @NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor,
            @NonNull ShellExecutor animExecutor) {
        startSurfaceAnimation(animations, mRotateAlphaAnimation, mAnimLeash, finishCallback,
                mTransactionPool, mainExecutor, animExecutor, null /* position */,
                0 /* cornerRadius */, null /* clipRect */);
    }

    private void startColorAnimation(float animationScale, @NonNull ShellExecutor animExecutor) {
        int colorTransitionMs = mContext.getResources().getInteger(
                R.integer.config_screen_rotation_color_transition);
@@ -351,14 +388,13 @@ class ScreenRotationAnimation {
                t.remove(mScreenshotLayer);
            }
            mScreenshotLayer = null;

        }
        if (mBackColorSurface != null) {
            if (mBackColorSurface.isValid()) {
                t.remove(mBackColorSurface);
            }
            mBackColorSurface = null;
        }
        }
        t.apply();
        mTransactionPool.release(t);
    }