diff options
4 files changed, 133 insertions, 77 deletions
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml index edf000b5e68a..bbbbe6987adf 100644 --- a/libs/WindowManager/Shell/res/values/config.xml +++ b/libs/WindowManager/Shell/res/values/config.xml @@ -52,6 +52,12 @@ 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: fade out icon --> + <integer name="starting_window_app_reveal_icon_fade_out_duration">133</integer> + + <!-- Animation duration when exit starting window: reveal app --> + <integer name="starting_window_app_reveal_anim_delay">83</integer> + <!-- Animation duration when exit starting window: reveal app --> - <integer name="starting_window_app_reveal_anim_duration">333</integer> + <integer name="starting_window_app_reveal_anim_duration">266</integer> </resources> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java index 3fe57c61c0bb..c303a33afc78 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java @@ -20,6 +20,7 @@ import static android.view.View.GONE; import android.animation.Animator; import android.animation.ValueAnimator; +import android.content.Context; import android.graphics.BlendMode; import android.graphics.Canvas; import android.graphics.Color; @@ -29,6 +30,7 @@ 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; @@ -38,10 +40,10 @@ import android.view.ViewGroup; import android.view.WindowManager; import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; -import android.view.animation.Transformation; -import android.view.animation.TranslateYAnimation; import android.window.SplashScreenView; +import com.android.wm.shell.R; +import com.android.wm.shell.animation.Interpolators; import com.android.wm.shell.common.TransactionPool; /** @@ -53,52 +55,64 @@ 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 APP_EXIT_INTERPOLATOR = new PathInterpolator(0f, 0f, 0f, 1f); + 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 Matrix mTmpTransform = new Matrix(); private final SurfaceControl mFirstWindowSurface; private final Rect mFirstWindowFrame = new Rect(); private final SplashScreenView mSplashScreenView; private final int mMainWindowShiftLength; - private final int mAppDuration; + private final int mIconFadeOutDuration; + private final int mAppRevealDelay; + private final int mAppRevealDuration; + private final int mAnimationDuration; + private final float mIconStartAlpha; private final TransactionPool mTransactionPool; private ValueAnimator mMainAnimator; private ShiftUpAnimation mShiftUpAnimation; + private RadialVanishAnimation mRadialVanishAnimation; private Runnable mFinishCallback; - SplashScreenExitAnimation(SplashScreenView view, SurfaceControl leash, Rect frame, - int appDuration, int mainWindowShiftLength, TransactionPool pool, - Runnable handleFinish) { + SplashScreenExitAnimation(Context context, SplashScreenView view, SurfaceControl leash, + Rect frame, int mainWindowShiftLength, TransactionPool pool, Runnable handleFinish) { mSplashScreenView = view; mFirstWindowSurface = leash; if (frame != null) { mFirstWindowFrame.set(frame); } - mAppDuration = appDuration; + + View iconView = view.getIconView(); + if (iconView == null) { + mIconFadeOutDuration = 0; + mIconStartAlpha = 0; + mAppRevealDelay = 0; + } else { + iconView.setLayerType(View.LAYER_TYPE_HARDWARE, null); + mIconFadeOutDuration = context.getResources().getInteger( + R.integer.starting_window_app_reveal_icon_fade_out_duration); + mAppRevealDelay = context.getResources().getInteger( + R.integer.starting_window_app_reveal_anim_delay); + mIconStartAlpha = iconView.getAlpha(); + } + mAppRevealDuration = context.getResources().getInteger( + R.integer.starting_window_app_reveal_anim_duration); + mAnimationDuration = Math.max(mIconFadeOutDuration, mAppRevealDelay + mAppRevealDuration); mMainWindowShiftLength = mainWindowShiftLength; mFinishCallback = handleFinish; mTransactionPool = pool; } void startAnimations() { - prepareRevealAnimation(); - if (mMainAnimator != null) { - mMainAnimator.start(); - } - if (mShiftUpAnimation != null) { - mShiftUpAnimation.start(); - } + mMainAnimator = createAnimator(); + mMainAnimator.start(); } - // reveal splash screen, shift up main window - private void prepareRevealAnimation() { - // splash screen - mMainAnimator = ValueAnimator.ofFloat(0f, 1f); - mMainAnimator.setDuration(mAppDuration); - mMainAnimator.setInterpolator(APP_EXIT_INTERPOLATOR); - mMainAnimator.addListener(this); - + // 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; @@ -106,14 +120,13 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener { final int halfWidth = mSplashScreenView.getWidth() / 2; final int endRadius = (int) (0.5 + (1f / transparentRatio * (int) Math.sqrt(finalVerticalLength * finalVerticalLength + halfWidth * halfWidth))); - final RadialVanishAnimation radialVanishAnimation = new RadialVanishAnimation( - mSplashScreenView, mMainAnimator); - radialVanishAnimation.setCircleCenter(halfWidth, verticalCircleCenter); - radialVanishAnimation.setRadius(0/* initRadius */, endRadius); - final int[] colors = {Color.TRANSPARENT, Color.TRANSPARENT, Color.WHITE}; + final int[] colors = {Color.WHITE, Color.WHITE, Color.TRANSPARENT}; final float[] stops = {0f, transparentRatio, 1f}; - radialVanishAnimation.setRadialPaintParam(colors, stops); - radialVanishAnimation.setReady(); + + 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 @@ -128,38 +141,47 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener { mSplashScreenView.addView(occludeHoleView, params); mShiftUpAnimation = new ShiftUpAnimation(0, -mMainWindowShiftLength, occludeHoleView); - mShiftUpAnimation.setDuration(mAppDuration); - mShiftUpAnimation.setInterpolator(APP_EXIT_INTERPOLATOR); - - occludeHoleView.setAnimation(mShiftUpAnimation); } + + 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 boolean mReady; 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, ValueAnimator animator) { + RadialVanishAnimation(SplashScreenView target) { super(target.getContext()); mView = target; - animator.addUpdateListener((animation) -> { - if (mVanishPaint.getShader() == null) { - return; - } - final float value = (float) animation.getAnimatedValue(); - final float scale = (mFinishRadius - mInitRadius) * value + mInitRadius; - mVanishMatrix.setScale(scale, scale); - mVanishMatrix.postTranslate(mCircleCenter.x, mCircleCenter.y); - mVanishPaint.getShader().setLocalMatrix(mVanishMatrix); - postInvalidate(); - }); 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) { @@ -184,38 +206,44 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener { new RadialGradient(0, 0, 1, colors, stops, Shader.TileMode.CLAMP); mVanishPaint.setShader(rShader); if (!DEBUG_EXIT_ANIMATION_BLEND) { - mVanishPaint.setBlendMode(BlendMode.MODULATE); + // 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); } } - void setReady() { - mReady = true; - } - @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); - if (mReady) { - canvas.drawRect(0, 0, mView.getWidth(), mView.getHeight(), mVanishPaint); - } + canvas.drawRect(0, 0, mView.getWidth(), mView.getHeight(), mVanishPaint); } } - private final class ShiftUpAnimation extends TranslateYAnimation { - final SyncRtSurfaceTransactionApplier mApplier; - ShiftUpAnimation(float fromYDelta, float toYDelta, View targetView) { - super(fromYDelta, toYDelta); - mApplier = new SyncRtSurfaceTransactionApplier(targetView); + 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); } - @Override - protected void applyTransformation(float interpolatedTime, Transformation t) { - super.applyTransformation(interpolatedTime, t); - + void onAnimationProgress(float linearProgress) { if (mFirstWindowSurface == null || !mFirstWindowSurface.isValid()) { return; } - mTmpTransform.set(t.getMatrix()); + + 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(); @@ -290,4 +318,32 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener { public void onAnimationRepeat(Animator animation) { // ignore } + + private void onAnimationProgress(float linearProgress) { + View iconView = mSplashScreenView.getIconView(); + if (iconView != null) { + final float iconProgress = ICON_INTERPOLATOR.getInterpolation( + getProgress(linearProgress, 0 /* delay */, mIconFadeOutDuration)); + iconView.setAlpha(mIconStartAlpha * (1 - iconProgress)); + } + + 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 + ); + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java index e656f43cfe35..fd6f0ad99e66 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java @@ -74,16 +74,14 @@ public class SplashscreenContentDrawer { private int mDefaultIconSize; private int mBrandingImageWidth; private int mBrandingImageHeight; - private final int mAppRevealDuration; private int mMainWindowShiftLength; private final TransactionPool mTransactionPool; private final SplashScreenWindowAttrs mTmpAttrs = new SplashScreenWindowAttrs(); private final Handler mSplashscreenWorkerHandler; - SplashscreenContentDrawer(Context context, int appRevealAnimDuration, TransactionPool pool) { + SplashscreenContentDrawer(Context context, TransactionPool pool) { mContext = context; mIconProvider = new IconProvider(context); - mAppRevealDuration = appRevealAnimDuration; mTransactionPool = pool; // Initialize Splashscreen worker thread @@ -671,9 +669,8 @@ public class SplashscreenContentDrawer { */ void applyExitAnimation(SplashScreenView view, SurfaceControl leash, Rect frame, Runnable finishCallback) { - final SplashScreenExitAnimation animation = new SplashScreenExitAnimation(view, leash, - frame, mAppRevealDuration, mMainWindowShiftLength, mTransactionPool, - finishCallback); + final SplashScreenExitAnimation animation = new SplashScreenExitAnimation(mContext, view, + leash, frame, mMainWindowShiftLength, mTransactionPool, finishCallback); animation.startAnimations(); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java index b7a0339aa93d..8fa2236f7fa1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java @@ -116,10 +116,7 @@ public class StartingSurfaceDrawer { mContext = context; mDisplayManager = mContext.getSystemService(DisplayManager.class); mSplashScreenExecutor = splashScreenExecutor; - final int appRevealAnimDuration = context.getResources().getInteger( - com.android.wm.shell.R.integer.starting_window_app_reveal_anim_duration); - mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext, appRevealAnimDuration, - pool); + mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext, pool); mSplashScreenExecutor.execute(() -> mChoreographer = Choreographer.getInstance()); } |