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

Commit 3dfd0644 authored by Vadim Caen's avatar Vadim Caen Committed by Automerger Merge Worker
Browse files

Merge "Support enable default splash screen reveal aninatmion" into sc-dev am: 279e0669

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

Change-Id: I21f4c677b559b552d60231732c8603856160d992
parents 999bd81c 279e0669
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ public final class SplashScreenView extends FrameLayout {
    private static final boolean DEBUG = false;

    private boolean mNotCopyable;
    private boolean mRevealAnimationSupported = true;
    private int mInitBackgroundColor;
    private int mInitIconBackgroundColor;
    private View mIconView;
@@ -263,6 +264,25 @@ public final class SplashScreenView extends FrameLayout {
        return !mNotCopyable;
    }

    /**
     * If set to true, indicates to the system that this view can be dismissed by playing the
     * Reveal animation.
     * <p>
     * If the exit animation is handled by the client, the animation won't be played anyway.
     * @hide
     */
    public void setRevealAnimationSupported(boolean support) {
        mRevealAnimationSupported = support;
    }

    /**
     * Whether this view support reveal animation.
     * @hide
     */
    public boolean isRevealAnimationSupported() {
        return mRevealAnimationSupported;
    }

    /**
     * Returns the duration of the icon animation if icon is animatable.
     *
+0 −3
Original line number Diff line number Diff line
@@ -52,9 +52,6 @@
     when the PIP menu is shown in center. -->
    <string translatable="false" name="pip_menu_bounds">"596 280 1324 690"</string>

    <!-- Animation duration when exit starting window: icon going away -->
    <integer name="starting_window_icon_exit_anim_duration">166</integer>

    <!-- Animation duration when exit starting window: reveal app -->
    <integer name="starting_window_app_reveal_anim_duration">333</integer>
</resources>
+51 −86
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */
package com.android.wm.shell.startingsurface;

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

import android.animation.Animator;
@@ -29,13 +30,12 @@ import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.Shader;
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.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import android.view.animation.Transformation;
@@ -53,51 +53,36 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener {
    private static final boolean DEBUG_EXIT_ANIMATION_BLEND = false;
    private static final String TAG = StartingSurfaceDrawer.TAG;

    private static final Interpolator ICON_EXIT_INTERPOLATOR = new PathInterpolator(1f, 0f, 1f, 1f);
    private static final Interpolator APP_EXIT_INTERPOLATOR = new PathInterpolator(0f, 0f, 0f, 1f);

    private static final int EXTRA_REVEAL_DELAY = 133;
    private final Matrix mTmpTransform = new Matrix();
    private final float[] mTmpFloat9 = new float[9];
    private SurfaceControl mFirstWindowSurface;
    private final SurfaceControl mFirstWindowSurface;
    private final Rect mFirstWindowFrame = new Rect();
    private final SplashScreenView mSplashScreenView;
    private final int mMainWindowShiftLength;
    private final int mIconShiftLength;
    private final int mAppDuration;
    private final int mIconDuration;
    private final TransactionPool mTransactionPool;

    private ValueAnimator mMainAnimator;
    private Animation mShiftUpAnimation;
    private AnimationSet mIconAnimationSet;
    private ShiftUpAnimation mShiftUpAnimation;
    private Runnable mFinishCallback;

    SplashScreenExitAnimation(SplashScreenView view, SurfaceControl leash, Rect frame,
            int appDuration, int iconDuration, int mainWindowShiftLength, int iconShiftLength,
            TransactionPool pool, Runnable handleFinish) {
            int appDuration, int mainWindowShiftLength, TransactionPool pool,
            Runnable handleFinish) {
        mSplashScreenView = view;
        mFirstWindowSurface = leash;
        if (frame != null) {
            mFirstWindowFrame.set(frame);
        }
        mAppDuration = appDuration;
        mIconDuration = iconDuration;
        mMainWindowShiftLength = mainWindowShiftLength;
        mIconShiftLength = iconShiftLength;
        mFinishCallback = handleFinish;
        mTransactionPool = pool;
    }

    void prepareAnimations() {
        prepareRevealAnimation();
        prepareShiftAnimation();
    }

    void startAnimations() {
        if (mIconAnimationSet != null) {
            mIconAnimationSet.start();
        }
        prepareRevealAnimation();
        if (mMainAnimator != null) {
            mMainAnimator.start();
        }
@@ -114,8 +99,7 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener {
        mMainAnimator.setInterpolator(APP_EXIT_INTERPOLATOR);
        mMainAnimator.addListener(this);

        final int startDelay = mIconDuration + EXTRA_REVEAL_DELAY;
        final float transparentRatio = 0.95f;
        final float transparentRatio = 0.8f;
        final int globalHeight = mSplashScreenView.getHeight();
        final int verticalCircleCenter = 0;
        final int finalVerticalLength = globalHeight - verticalCircleCenter;
@@ -130,9 +114,8 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener {
        final float[] stops = {0f, transparentRatio, 1f};
        radialVanishAnimation.setRadialPaintParam(colors, stops);
        radialVanishAnimation.setReady();
        mMainAnimator.setStartDelay(startDelay);

        if (mFirstWindowSurface != null) {
        if (mFirstWindowSurface != null && mFirstWindowSurface.isValid()) {
            // shift up main window
            View occludeHoleView = new View(mSplashScreenView.getContext());
            if (DEBUG_EXIT_ANIMATION_BLEND) {
@@ -144,59 +127,16 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener {
                    WindowManager.LayoutParams.MATCH_PARENT, mMainWindowShiftLength);
            mSplashScreenView.addView(occludeHoleView, params);

            mShiftUpAnimation = new ShiftUpAnimation(0, -mMainWindowShiftLength);
            mShiftUpAnimation = new ShiftUpAnimation(0, -mMainWindowShiftLength, occludeHoleView);
            mShiftUpAnimation.setDuration(mAppDuration);
            mShiftUpAnimation.setInterpolator(APP_EXIT_INTERPOLATOR);
            mShiftUpAnimation.setStartOffset(startDelay);

            occludeHoleView.setAnimation(mShiftUpAnimation);
        }
    }

    // shift down icon and branding view
    private void prepareShiftAnimation() {
        final View iconView = mSplashScreenView.getIconView();
        if (iconView == null) {
            return;
        }
        if (mIconShiftLength > 0) {
            mIconAnimationSet = new AnimationSet(true /* shareInterpolator */);
            if (DEBUG_EXIT_ANIMATION) {
                Slog.v(TAG, "first exit animation, shift length: " + mIconShiftLength);
            }
            mIconAnimationSet.addAnimation(new TranslateYAnimation(0, mIconShiftLength));
            mIconAnimationSet.addAnimation(new AlphaAnimation(1, 0));
            mIconAnimationSet.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {

                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    if (DEBUG_EXIT_ANIMATION) {
                        Slog.v(TAG, "first exit animation finished");
                    }
                    iconView.post(() -> iconView.setVisibility(GONE));
                }

                @Override
                public void onAnimationRepeat(Animation animation) {
                    // ignore
                }
            });
            mIconAnimationSet.setDuration(mIconDuration);
            mIconAnimationSet.setInterpolator(ICON_EXIT_INTERPOLATOR);
            iconView.setAnimation(mIconAnimationSet);
            final View brandingView = mSplashScreenView.getBrandingView();
            if (brandingView != null) {
                brandingView.setAnimation(mIconAnimationSet);
            }
        }
    }

    private static class RadialVanishAnimation extends View {
        private SplashScreenView mView;
        private final SplashScreenView mView;
        private int mInitRadius;
        private int mFinishRadius;
        private boolean mReady;
@@ -217,7 +157,7 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener {
                mVanishMatrix.setScale(scale, scale);
                mVanishMatrix.postTranslate(mCircleCenter.x, mCircleCenter.y);
                mVanishPaint.getShader().setLocalMatrix(mVanishMatrix);
                mView.postInvalidate();
                postInvalidate();
            });
            mView.addView(this);
        }
@@ -262,28 +202,57 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener {
    }

    private final class ShiftUpAnimation extends TranslateYAnimation {
        ShiftUpAnimation(float fromYDelta, float toYDelta) {
        final SyncRtSurfaceTransactionApplier mApplier;
        ShiftUpAnimation(float fromYDelta, float toYDelta, View targetView) {
            super(fromYDelta, toYDelta);
            mApplier = new SyncRtSurfaceTransactionApplier(targetView);
        }

        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            super.applyTransformation(interpolatedTime, t);

            if (mFirstWindowSurface == null) {
            if (mFirstWindowSurface == null || !mFirstWindowSurface.isValid()) {
                return;
            }
            mTmpTransform.set(t.getMatrix());

            // 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);
            tx.setMatrix(mFirstWindowSurface, mTmpTransform, mTmpFloat9);
            // TODO set the vsyncId to ensure the transaction doesn't get applied too early.
            //  Additionally, do you want to have this synchronized with your view animations?
            //  If so, you'll need to use SyncRtSurfaceTransactionApplier
            tx.apply();

            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();
            tx.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId());

            SyncRtSurfaceTransactionApplier.SurfaceParams
                    params = new SyncRtSurfaceTransactionApplier.SurfaceParams
                    .Builder(mFirstWindowSurface)
                    .withWindowCrop(null)
                    .withMergeTransaction(tx)
                    .build();
            mApplier.scheduleApply(params);
            mTransactionPool.release(tx);

            Choreographer.getSfInstance().postCallback(CALLBACK_COMMIT,
                    mFirstWindowSurface::release, null);
        }
    }

    private void reset() {
@@ -297,12 +266,8 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener {
                mFinishCallback = null;
            }
        });
        if (mFirstWindowSurface != null) {
            final SurfaceControl.Transaction tx = mTransactionPool.acquire();
            tx.setWindowCrop(mFirstWindowSurface, null);
            tx.apply();
            mFirstWindowSurface.release();
            mFirstWindowSurface = null;
        if (mShiftUpAnimation != null) {
            mShiftUpAnimation.finish();
        }
    }

+4 −14
Original line number Diff line number Diff line
@@ -75,20 +75,15 @@ public class SplashscreenContentDrawer {
    private int mBrandingImageWidth;
    private int mBrandingImageHeight;
    private final int mAppRevealDuration;
    private final int mIconExitDuration;
    private int mMainWindowShiftLength;
    private int mIconNormalExitDistance;
    private int mIconEarlyExitDistance;
    private final TransactionPool mTransactionPool;
    private final SplashScreenWindowAttrs mTmpAttrs = new SplashScreenWindowAttrs();
    private final Handler mSplashscreenWorkerHandler;

    SplashscreenContentDrawer(Context context, int iconExitAnimDuration, int appRevealAnimDuration,
            TransactionPool pool) {
    SplashscreenContentDrawer(Context context, int appRevealAnimDuration, TransactionPool pool) {
        mContext = context;
        mIconProvider = new IconProvider(context);
        mAppRevealDuration = appRevealAnimDuration;
        mIconExitDuration = iconExitAnimDuration;
        mTransactionPool = pool;

        // Initialize Splashscreen worker thread
@@ -139,10 +134,6 @@ public class SplashscreenContentDrawer {
                com.android.wm.shell.R.dimen.starting_surface_brand_image_height);
        mMainWindowShiftLength = mContext.getResources().getDimensionPixelSize(
                com.android.wm.shell.R.dimen.starting_surface_exit_animation_window_shift_length);
        mIconNormalExitDistance = mContext.getResources().getDimensionPixelSize(
                com.android.wm.shell.R.dimen.starting_surface_normal_exit_icon_distance);
        mIconEarlyExitDistance = mContext.getResources().getDimensionPixelSize(
                com.android.wm.shell.R.dimen.starting_surface_early_exit_icon_distance);
    }

    private int getSystemBGColor() {
@@ -406,6 +397,7 @@ public class SplashscreenContentDrawer {
            }
            if (mEmptyView) {
                splashScreenView.setNotCopyable();
                splashScreenView.setRevealAnimationSupported(false);
            }
            splashScreenView.makeSystemUIColorsTransparent();
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
@@ -678,12 +670,10 @@ public class SplashscreenContentDrawer {
     * Create and play the default exit animation for splash screen view.
     */
    void applyExitAnimation(SplashScreenView view, SurfaceControl leash,
            Rect frame, boolean isEarlyExit, Runnable finishCallback) {
            Rect frame, Runnable finishCallback) {
        final SplashScreenExitAnimation animation = new SplashScreenExitAnimation(view, leash,
                frame, mAppRevealDuration, mIconExitDuration, mMainWindowShiftLength,
                isEarlyExit ? mIconEarlyExitDistance : mIconNormalExitDistance, mTransactionPool,
                frame, mAppRevealDuration, mMainWindowShiftLength, mTransactionPool,
                finishCallback);
        animation.prepareAnimations();
        animation.startAnimations();
    }
}
+20 −23
Original line number Diff line number Diff line
@@ -35,7 +35,7 @@ import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.os.IBinder;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.util.Slog;
import android.util.SparseArray;
@@ -106,6 +106,8 @@ public class StartingSurfaceDrawer {
    private final SplashscreenContentDrawer mSplashscreenContentDrawer;
    private Choreographer mChoreographer;

    private static final boolean DEBUG_ENABLE_REVEAL_ANIMATION =
            SystemProperties.getBoolean("persist.debug.enable_reveal_animation", false);
    /**
     * @param splashScreenExecutor The thread used to control add and remove starting window.
     */
@@ -114,12 +116,10 @@ public class StartingSurfaceDrawer {
        mContext = context;
        mDisplayManager = mContext.getSystemService(DisplayManager.class);
        mSplashScreenExecutor = splashScreenExecutor;
        final int iconExitAnimDuration = context.getResources().getInteger(
                com.android.wm.shell.R.integer.starting_window_icon_exit_anim_duration);
        final int appRevealAnimDuration = context.getResources().getInteger(
                com.android.wm.shell.R.integer.starting_window_app_reveal_anim_duration);
        mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext, iconExitAnimDuration,
                appRevealAnimDuration, pool);
        mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext, appRevealAnimDuration,
                pool);
        mSplashScreenExecutor.execute(() -> mChoreographer = Choreographer.getInstance());
    }

@@ -467,20 +467,24 @@ public class StartingSurfaceDrawer {
                if (DEBUG_SPLASH_SCREEN) {
                    Slog.v(TAG, "Removing splash screen window for task: " + taskId);
                }
                if (record.mContentView != null) {
                    if (leash != null || playRevealAnimation) {
                if (record.mContentView != null
                        && record.mContentView.isRevealAnimationSupported()) {
                    if (playRevealAnimation) {
                        if (DEBUG_ENABLE_REVEAL_ANIMATION) {
                            mSplashscreenContentDrawer.applyExitAnimation(record.mContentView,
                                leash, frame, record.isEarlyExit(),
                                    leash, frame,
                                    () -> removeWindowInner(record.mDecorView, true));
                        } else {
                        // TODO(183004107) Always hide decorView when playRevealAnimation is enabled
                        //  from TaskOrganizerController#removeStartingWindow
                        // the SplashScreenView has been copied to client, skip default exit
                        // animation
                            // using the default exit animation from framework
                            removeWindowInner(record.mDecorView, false);
                        }
                    } else {
                    // no animation will be applied
                        // the SplashScreenView has been copied to client, hide the view to skip
                        // default exit animation
                        removeWindowInner(record.mDecorView, true);
                    }
                } else {
                    // this is a blank splash screen, don't apply reveal animation
                    removeWindowInner(record.mDecorView, false);
                }
            }
@@ -514,12 +518,10 @@ public class StartingSurfaceDrawer {
     * Record the view or surface for a starting window.
     */
    private static class StartingWindowRecord {
        private static final long EARLY_START_MINIMUM_TIME_MS = 250;
        private final View mDecorView;
        private final TaskSnapshotWindow mTaskSnapshotWindow;
        private SplashScreenView mContentView;
        private boolean mSetSplashScreen;
        private long mContentCreateTime;

        StartingWindowRecord(View decorView, TaskSnapshotWindow taskSnapshotWindow) {
            mDecorView = decorView;
@@ -531,12 +533,7 @@ public class StartingSurfaceDrawer {
                return;
            }
            mContentView = splashScreenView;
            mContentCreateTime = SystemClock.uptimeMillis();
            mSetSplashScreen = true;
        }

        boolean isEarlyExit() {
            return SystemClock.uptimeMillis() - mContentCreateTime < EARLY_START_MINIMUM_TIME_MS;
        }
    }
}
Loading