From 2161985b506c87804b432101ab252e3b61d8b107 Mon Sep 17 00:00:00 2001 From: Federico Baron Date: Mon, 12 Dec 2022 14:38:31 -0800 Subject: [PATCH] Add icon scale and alpha animation for entering downloading state from pending state When we enter downloading state from being in pending state, we want to run an animation that animates the process of scaling down the icon as well as removing the overlay with an animation Bug: 254858049 Test: Download a couple of apps with ENABLE_DOWNLOAD_APP_UX_V2 flag on Change-Id: Ie4f378874aa3cf6597c02b4d7043a34eb51d838c --- .../graphics/PreloadIconDrawable.java | 72 +++++++++++++------ 1 file changed, 50 insertions(+), 22 deletions(-) diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java index 9a961ca300..de47cb5057 100644 --- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java +++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java @@ -17,6 +17,7 @@ package com.android.launcher3.graphics; +import static com.android.launcher3.anim.Interpolators.EMPHASIZED; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.config.FeatureFlags.ENABLE_DOWNLOAD_APP_UX_V2; @@ -39,6 +40,7 @@ import android.util.Property; import com.android.launcher3.R; import com.android.launcher3.Utilities; +import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.icons.FastBitmapDrawable; import com.android.launcher3.icons.GraphicsUtils; import com.android.launcher3.model.data.ItemInfoWithIcon; @@ -72,12 +74,13 @@ public class PreloadIconDrawable extends FastBitmapDrawable implements Runnable private static final int DISABLED_ICON_ALPHA = (int) (0.6f * MAX_PAINT_ALPHA); private static final long DURATION_SCALE = 500; + private static final long SCALE_AND_ALPHA_ANIM_DURATION = 500; // The smaller the number, the faster the animation would be. // Duration = COMPLETE_ANIM_FRACTION * DURATION_SCALE private static final float COMPLETE_ANIM_FRACTION = 0.3f; - private static final float SMALL_SCALE = ENABLE_DOWNLOAD_APP_UX_V2.get() ? 0.85f : 0.7f; + private static final float SMALL_SCALE = ENABLE_DOWNLOAD_APP_UX_V2.get() ? 0.867f : 0.7f; private static final float PROGRESS_STROKE_SCALE = 0.075f; private static final int PRELOAD_ACCENT_COLOR_INDEX = 0; @@ -110,12 +113,13 @@ public class PreloadIconDrawable extends FastBitmapDrawable implements Runnable private int mTrackAlpha; private float mTrackLength; - private float mIconScale; private boolean mRanFinishAnimation; - private int mOverlayAlpha = 127; - private int mRefreshRateMillis; + private final int mRefreshRateMillis; + private final AnimatedFloat mIconScale = new AnimatedFloat(this::invalidateSelf); + private final AnimatedFloat mOverlayAlpha = new AnimatedFloat(this::updateOverlayAlpha); + private boolean mShouldAnimateScaleAndAlpha; // Progress of the internal state. [0, 1] indicates the fraction of completed progress, // [1, (1 + COMPLETE_ANIM_FRACTION)] indicates the progress of zoom animation. @@ -155,6 +159,12 @@ public class PreloadIconDrawable extends FastBitmapDrawable implements Runnable mIsDarkMode = isDarkMode; mRefreshRateMillis = refreshRateMillis; + // If it's a pending app we will animate scale and alpha when it's no longer pending. + if (ENABLE_DOWNLOAD_APP_UX_V2.get() && info.getProgressLevel() == 0) { + mShouldAnimateScaleAndAlpha = true; + mOverlayAlpha.updateValue(127); + } + setLevel(info.getProgressLevel()); setIsStartable(info.isAppStartable()); } @@ -199,7 +209,8 @@ public class PreloadIconDrawable extends FastBitmapDrawable implements Runnable canvas.drawPath(mScaledProgressPath, mProgressPaint); int saveCount = canvas.save(); - canvas.scale(mIconScale, mIconScale, bounds.exactCenterX(), bounds.exactCenterY()); + canvas.scale( + mIconScale.value, mIconScale.value, bounds.exactCenterX(), bounds.exactCenterY()); super.drawInternal(canvas, bounds); canvas.restoreToCount(saveCount); @@ -301,18 +312,34 @@ public class PreloadIconDrawable extends FastBitmapDrawable implements Runnable * - only icon is drawn in normal state */ private void setInternalProgress(float progress) { + // Animate scale and alpha from pending to downloading state. + if (ENABLE_DOWNLOAD_APP_UX_V2.get() + && mShouldAnimateScaleAndAlpha && mInternalStateProgress == 0 && progress > 0) { + Animator iconScaleAnimator = mIconScale.animateToValue(SMALL_SCALE); + iconScaleAnimator.setDuration(SCALE_AND_ALPHA_ANIM_DURATION); + iconScaleAnimator.setInterpolator(EMPHASIZED); + iconScaleAnimator.start(); + + Animator overlayAlphaAnimator = mOverlayAlpha.animateToValue(0); + overlayAlphaAnimator.setDuration(SCALE_AND_ALPHA_ANIM_DURATION); + overlayAlphaAnimator.setInterpolator(EMPHASIZED); + overlayAlphaAnimator.start(); + } + mInternalStateProgress = progress; if (progress <= 0) { - mIconScale = ENABLE_DOWNLOAD_APP_UX_V2.get() ? 1 : SMALL_SCALE; + mIconScale.updateValue(ENABLE_DOWNLOAD_APP_UX_V2.get() ? 1 : SMALL_SCALE); mScaledTrackPath.reset(); mTrackAlpha = MAX_PAINT_ALPHA; } else if (progress < 1) { mPathMeasure.getSegment(0, progress * mTrackLength, mScaledProgressPath, true); if (ENABLE_DOWNLOAD_APP_UX_V2.get()) { - mPaint.setColorFilter(null); mPathMeasure.getSegment(0, mTrackLength, mScaledTrackPath, true); } - mIconScale = SMALL_SCALE; + + if (!ENABLE_DOWNLOAD_APP_UX_V2.get() || !mShouldAnimateScaleAndAlpha) { + mIconScale.updateValue(SMALL_SCALE); + } mTrackAlpha = MAX_PAINT_ALPHA; } else { setIsDisabled(mItem.isDisabled()); @@ -321,11 +348,11 @@ public class PreloadIconDrawable extends FastBitmapDrawable implements Runnable if (fraction >= 1) { // Animation has completed - mIconScale = 1; + mIconScale.updateValue(1); mTrackAlpha = 0; } else { mTrackAlpha = Math.round((1 - fraction) * MAX_PAINT_ALPHA); - mIconScale = SMALL_SCALE + (1 - SMALL_SCALE) * fraction; + mIconScale.updateValue(SMALL_SCALE + (1 - SMALL_SCALE) * fraction); } } invalidateSelf(); @@ -370,9 +397,7 @@ public class PreloadIconDrawable extends FastBitmapDrawable implements Runnable if (!ENABLE_DOWNLOAD_APP_UX_V2.get() || mInternalStateProgress > 0) { return; } - if (applyPendingIconOverlay()) { - invalidateSelf(); - } else { + if (!applyPendingIconOverlay()) { reschedule(); } } @@ -408,7 +433,7 @@ public class PreloadIconDrawable extends FastBitmapDrawable implements Runnable long waveMotionDelay = (mItem.cellX * WAVE_MOTION_DELAY_FACTOR_MILLIS) + (mItem.cellY * WAVE_MOTION_DELAY_FACTOR_MILLIS); long time = SystemClock.uptimeMillis(); - int newAlpha = (int) Utilities.mapBoundToRange( + float newAlpha = Utilities.mapBoundToRange( (float) (time + waveMotionDelay) % ALPHA_DURATION_MILLIS, 0, ALPHA_DURATION_MILLIS, @@ -416,22 +441,25 @@ public class PreloadIconDrawable extends FastBitmapDrawable implements Runnable MAX_PAINT_ALPHA, LINEAR); if (newAlpha > OVERLAY_ALPHA_RANGE) { - newAlpha = (int) (OVERLAY_ALPHA_RANGE - (newAlpha % OVERLAY_ALPHA_RANGE)); + newAlpha = (OVERLAY_ALPHA_RANGE - (newAlpha % OVERLAY_ALPHA_RANGE)); } boolean invalidate = false; - if (mOverlayAlpha != newAlpha) { - mOverlayAlpha = newAlpha; - int overlayColor = mIsDarkMode ? 0 : 255; - int currArgb = Color.argb(mOverlayAlpha, overlayColor, overlayColor, overlayColor); - mPaint.setColorFilter(COLOR_FILTER_MAP.computeIfAbsent( - currArgb, - FILTER_FACTORY)); + if ((int) mOverlayAlpha.value != newAlpha) { + mOverlayAlpha.updateValue(newAlpha); invalidate = true; } return invalidate; } + private void updateOverlayAlpha() { + int overlayColor = mIsDarkMode ? 0 : 255; + int currArgb = + Color.argb((int) mOverlayAlpha.value, overlayColor, overlayColor, overlayColor); + mPaint.setColorFilter(COLOR_FILTER_MAP.computeIfAbsent(currArgb, FILTER_FACTORY)); + invalidateSelf(); + } + protected static class PreloadIconConstantState extends FastBitmapConstantState { protected final ItemInfoWithIcon mInfo;