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

Commit c14774d7 authored by Pat Manning's avatar Pat Manning Committed by Automerger Merge Worker
Browse files

Merge "Refactor SplashScreenAnimation so it can be reused in other parts of...

Merge "Refactor SplashScreenAnimation so it can be reused in other parts of the code." into tm-qpr-dev am: 934606c0

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19886504



Change-Id: I2a8cab7381118a00734363204338a149a68d2b4f
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 10c358b7 934606c0
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -45,6 +45,9 @@ filegroup {
        "src/com/android/wm/shell/util/**/*.java",
        "src/com/android/wm/shell/common/split/SplitScreenConstants.java",
        "src/com/android/wm/shell/sysui/ShellSharedConstants.java",
        "src/com/android/wm/shell/common/TransactionPool.java",
        "src/com/android/wm/shell/animation/Interpolators.java",
        "src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java",
    ],
    path: "src",
}
+4 −247
Original line number Diff line number Diff line
@@ -15,38 +15,20 @@
 */
package com.android.wm.shell.startingsurface;

import static android.view.Choreographer.CALLBACK_COMMIT;
import static android.view.View.GONE;

import static com.android.internal.jank.InteractionJankMonitor.CUJ_SPLASHSCREEN_EXIT_ANIM;

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.BlendMode;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.Shader;
import android.util.MathUtils;
import android.util.Slog;
import android.view.Choreographer;
import android.view.SurfaceControl;
import android.view.SyncRtSurfaceTransactionApplier;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import android.window.SplashScreenView;

import com.android.internal.jank.InteractionJankMonitor;
import com.android.wm.shell.R;
import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.common.TransactionPool;

/**
@@ -55,14 +37,8 @@ import com.android.wm.shell.common.TransactionPool;
 */
public class SplashScreenExitAnimation implements Animator.AnimatorListener {
    private static final boolean DEBUG_EXIT_ANIMATION = false;
    private static final boolean DEBUG_EXIT_ANIMATION_BLEND = false;
    private static final String TAG = StartingWindowController.TAG;

    private static final Interpolator ICON_INTERPOLATOR = new PathInterpolator(0.15f, 0f, 1f, 1f);
    private static final Interpolator MASK_RADIUS_INTERPOLATOR =
            new PathInterpolator(0f, 0f, 0.4f, 1f);
    private static final Interpolator SHIFT_UP_INTERPOLATOR = new PathInterpolator(0f, 0f, 0f, 1f);

    private final SurfaceControl mFirstWindowSurface;
    private final Rect mFirstWindowFrame = new Rect();
    private final SplashScreenView mSplashScreenView;
@@ -75,9 +51,6 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener {
    private final float mBrandingStartAlpha;
    private final TransactionPool mTransactionPool;

    private ValueAnimator mMainAnimator;
    private ShiftUpAnimation mShiftUpAnimation;
    private RadialVanishAnimation mRadialVanishAnimation;
    private Runnable mFinishCallback;

    SplashScreenExitAnimation(Context context, SplashScreenView view, SurfaceControl leash,
@@ -121,187 +94,10 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener {
    }

    void startAnimations() {
        mMainAnimator = createAnimator();
        mMainAnimator.start();
    }

    // fade out icon, reveal app, shift up main window
    private ValueAnimator createAnimator() {
        // reveal app
        final float transparentRatio = 0.8f;
        final int globalHeight = mSplashScreenView.getHeight();
        final int verticalCircleCenter = 0;
        final int finalVerticalLength = globalHeight - verticalCircleCenter;
        final int halfWidth = mSplashScreenView.getWidth() / 2;
        final int endRadius = (int) (0.5 + (1f / transparentRatio * (int)
                Math.sqrt(finalVerticalLength * finalVerticalLength + halfWidth * halfWidth)));
        final int[] colors = {Color.WHITE, Color.WHITE, Color.TRANSPARENT};
        final float[] stops = {0f, transparentRatio, 1f};

        mRadialVanishAnimation = new RadialVanishAnimation(mSplashScreenView);
        mRadialVanishAnimation.setCircleCenter(halfWidth, verticalCircleCenter);
        mRadialVanishAnimation.setRadius(0 /* initRadius */, endRadius);
        mRadialVanishAnimation.setRadialPaintParam(colors, stops);

        if (mFirstWindowSurface != null && mFirstWindowSurface.isValid()) {
            // shift up main window
            View occludeHoleView = new View(mSplashScreenView.getContext());
            if (DEBUG_EXIT_ANIMATION_BLEND) {
                occludeHoleView.setBackgroundColor(Color.BLUE);
            } else {
                occludeHoleView.setBackgroundColor(mSplashScreenView.getInitBackgroundColor());
            }
            final ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
                    WindowManager.LayoutParams.MATCH_PARENT, mMainWindowShiftLength);
            mSplashScreenView.addView(occludeHoleView, params);

            mShiftUpAnimation = new ShiftUpAnimation(0, -mMainWindowShiftLength, occludeHoleView);
        }

        ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
        animator.setDuration(mAnimationDuration);
        animator.setInterpolator(Interpolators.LINEAR);
        animator.addListener(this);
        animator.addUpdateListener(a -> onAnimationProgress((float) a.getAnimatedValue()));
        return animator;
    }

    private static class RadialVanishAnimation extends View {
        private final SplashScreenView mView;
        private int mInitRadius;
        private int mFinishRadius;

        private final Point mCircleCenter = new Point();
        private final Matrix mVanishMatrix = new Matrix();
        private final Paint mVanishPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

        RadialVanishAnimation(SplashScreenView target) {
            super(target.getContext());
            mView = target;
            mView.addView(this);
            mVanishPaint.setAlpha(0);
        }

        void onAnimationProgress(float linearProgress) {
            if (mVanishPaint.getShader() == null) {
                return;
            }

            final float radiusProgress = MASK_RADIUS_INTERPOLATOR.getInterpolation(linearProgress);
            final float alphaProgress = Interpolators.ALPHA_OUT.getInterpolation(linearProgress);
            final float scale = mInitRadius + (mFinishRadius - mInitRadius) * radiusProgress;

            mVanishMatrix.setScale(scale, scale);
            mVanishMatrix.postTranslate(mCircleCenter.x, mCircleCenter.y);
            mVanishPaint.getShader().setLocalMatrix(mVanishMatrix);
            mVanishPaint.setAlpha(Math.round(0xFF * alphaProgress));

            postInvalidate();
        }

        void setRadius(int initRadius, int finishRadius) {
            if (DEBUG_EXIT_ANIMATION) {
                Slog.v(TAG, "RadialVanishAnimation setRadius init: " + initRadius
                        + " final " + finishRadius);
            }
            mInitRadius = initRadius;
            mFinishRadius = finishRadius;
        }

        void setCircleCenter(int x, int y) {
            if (DEBUG_EXIT_ANIMATION) {
                Slog.v(TAG, "RadialVanishAnimation setCircleCenter x: " + x + " y " + y);
            }
            mCircleCenter.set(x, y);
        }

        void setRadialPaintParam(int[] colors, float[] stops) {
            // setup gradient shader
            final RadialGradient rShader =
                    new RadialGradient(0, 0, 1, colors, stops, Shader.TileMode.CLAMP);
            mVanishPaint.setShader(rShader);
            if (!DEBUG_EXIT_ANIMATION_BLEND) {
                // We blend the reveal gradient with the splash screen using DST_OUT so that the
                // splash screen is fully visible when radius = 0 (or gradient opacity is 0) and
                // fully invisible when radius = finishRadius AND gradient opacity is 1.
                mVanishPaint.setBlendMode(BlendMode.DST_OUT);
            }
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.drawRect(0, 0, mView.getWidth(), mView.getHeight(), mVanishPaint);
        }
    }

    private final class ShiftUpAnimation {
        private final float mFromYDelta;
        private final float mToYDelta;
        private final View mOccludeHoleView;
        private final SyncRtSurfaceTransactionApplier mApplier;
        private final Matrix mTmpTransform = new Matrix();

        ShiftUpAnimation(float fromYDelta, float toYDelta, View occludeHoleView) {
            mFromYDelta = fromYDelta;
            mToYDelta = toYDelta;
            mOccludeHoleView = occludeHoleView;
            mApplier = new SyncRtSurfaceTransactionApplier(occludeHoleView);
        }

        void onAnimationProgress(float linearProgress) {
            if (mFirstWindowSurface == null || !mFirstWindowSurface.isValid()
                    || !mSplashScreenView.isAttachedToWindow()) {
                return;
            }

            final float progress = SHIFT_UP_INTERPOLATOR.getInterpolation(linearProgress);
            final float dy = mFromYDelta + (mToYDelta - mFromYDelta) * progress;

            mOccludeHoleView.setTranslationY(dy);
            mTmpTransform.setTranslate(0 /* dx */, dy);

            // set the vsyncId to ensure the transaction doesn't get applied too early.
            final SurfaceControl.Transaction tx = mTransactionPool.acquire();
            tx.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId());
            mTmpTransform.postTranslate(mFirstWindowFrame.left,
                    mFirstWindowFrame.top + mMainWindowShiftLength);

            SyncRtSurfaceTransactionApplier.SurfaceParams
                    params = new SyncRtSurfaceTransactionApplier.SurfaceParams
                    .Builder(mFirstWindowSurface)
                    .withMatrix(mTmpTransform)
                    .withMergeTransaction(tx)
                    .build();
            mApplier.scheduleApply(params);

            mTransactionPool.release(tx);
        }

        void finish() {
            if (mFirstWindowSurface == null || !mFirstWindowSurface.isValid()) {
                return;
            }
            final SurfaceControl.Transaction tx = mTransactionPool.acquire();
            if (mSplashScreenView.isAttachedToWindow()) {
                tx.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId());

                SyncRtSurfaceTransactionApplier.SurfaceParams
                        params = new SyncRtSurfaceTransactionApplier.SurfaceParams
                        .Builder(mFirstWindowSurface)
                        .withWindowCrop(null)
                        .withMergeTransaction(tx)
                        .build();
                mApplier.scheduleApply(params);
            } else {
                tx.setWindowCrop(mFirstWindowSurface, null);
                tx.apply();
            }
            mTransactionPool.release(tx);

            Choreographer.getSfInstance().postCallback(CALLBACK_COMMIT,
                    mFirstWindowSurface::release, null);
        }
        SplashScreenExitAnimationUtils.startAnimations(mSplashScreenView, mFirstWindowSurface,
                mMainWindowShiftLength, mTransactionPool, mFirstWindowFrame, mAnimationDuration,
                mIconFadeOutDuration, mIconStartAlpha, mBrandingStartAlpha, mAppRevealDelay,
                mAppRevealDuration, this);
    }

    private void reset() {
@@ -316,9 +112,6 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener {
                mFinishCallback = null;
            }
        }
        if (mShiftUpAnimation != null) {
            mShiftUpAnimation.finish();
        }
    }

    @Override
@@ -342,40 +135,4 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener {
    public void onAnimationRepeat(Animator animation) {
        // ignore
    }

    private void onFadeOutProgress(float linearProgress) {
        final float iconProgress = ICON_INTERPOLATOR.getInterpolation(
                getProgress(linearProgress, 0 /* delay */, mIconFadeOutDuration));
        final View iconView = mSplashScreenView.getIconView();
        final View brandingView = mSplashScreenView.getBrandingView();
        if (iconView != null) {
            iconView.setAlpha(mIconStartAlpha * (1 - iconProgress));
        }
        if (brandingView != null) {
            brandingView.setAlpha(mBrandingStartAlpha * (1 - iconProgress));
        }
    }

    private void onAnimationProgress(float linearProgress) {
        onFadeOutProgress(linearProgress);

        final float revealLinearProgress = getProgress(linearProgress, mAppRevealDelay,
                mAppRevealDuration);

        if (mRadialVanishAnimation != null) {
            mRadialVanishAnimation.onAnimationProgress(revealLinearProgress);
        }

        if (mShiftUpAnimation != null) {
            mShiftUpAnimation.onAnimationProgress(revealLinearProgress);
        }
    }

    private float getProgress(float linearProgress, long delay, long duration) {
        return MathUtils.constrain(
                (linearProgress * (mAnimationDuration) - delay) / duration,
                0.0f,
                1.0f
        );
    }
}
+358 −0

File added.

Preview size limit exceeded, changes collapsed.