1 package com.android.quickstep.views; 2 3 import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; 4 import static com.android.launcher3.anim.Interpolators.LINEAR; 5 6 import android.animation.Animator; 7 import android.animation.AnimatorListenerAdapter; 8 import android.animation.ObjectAnimator; 9 import android.graphics.Canvas; 10 import android.graphics.ColorFilter; 11 import android.graphics.Paint; 12 import android.graphics.PixelFormat; 13 import android.graphics.PorterDuff; 14 import android.graphics.PorterDuffXfermode; 15 import android.graphics.Rect; 16 import android.graphics.RectF; 17 import android.graphics.drawable.Drawable; 18 import android.util.FloatProperty; 19 20 import com.android.launcher3.anim.Interpolators; 21 22 public class LiveTileOverlay extends Drawable { 23 24 private static final long ICON_ANIM_DURATION = 120; 25 26 private static final FloatProperty<LiveTileOverlay> PROGRESS = 27 new FloatProperty<LiveTileOverlay>("progress") { 28 @Override 29 public void setValue(LiveTileOverlay liveTileOverlay, float progress) { 30 liveTileOverlay.setIconAnimationProgress(progress); 31 } 32 33 @Override 34 public Float get(LiveTileOverlay liveTileOverlay) { 35 return liveTileOverlay.mIconAnimationProgress; 36 } 37 }; 38 39 private final Paint mPaint = new Paint(); 40 41 private Rect mBoundsRect = new Rect(); 42 private RectF mCurrentRect; 43 private float mCornerRadius; 44 private Drawable mIcon; 45 private Animator mIconAnimator; 46 47 private boolean mDrawEnabled = true; 48 private float mIconAnimationProgress = 0f; 49 LiveTileOverlay()50 public LiveTileOverlay() { 51 mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); 52 } 53 update(RectF currentRect, float cornerRadius)54 public void update(RectF currentRect, float cornerRadius) { 55 invalidateSelf(); 56 57 mCurrentRect = currentRect; 58 mCornerRadius = cornerRadius; 59 60 mCurrentRect.roundOut(mBoundsRect); 61 setBounds(mBoundsRect); 62 invalidateSelf(); 63 } 64 setIcon(Drawable icon)65 public void setIcon(Drawable icon) { 66 mIcon = icon; 67 } 68 startIconAnimation()69 public void startIconAnimation() { 70 if (mIconAnimator != null) { 71 mIconAnimator.cancel(); 72 } 73 // This animator must match the icon part of {@link TaskView#FOCUS_TRANSITION} animation. 74 mIconAnimator = ObjectAnimator.ofFloat(this, PROGRESS, 1); 75 mIconAnimator.setDuration(ICON_ANIM_DURATION).setInterpolator(LINEAR); 76 mIconAnimator.addListener(new AnimatorListenerAdapter() { 77 @Override 78 public void onAnimationEnd(Animator animation) { 79 mIconAnimator = null; 80 } 81 }); 82 mIconAnimator.start(); 83 } 84 cancelIconAnimation()85 public float cancelIconAnimation() { 86 if (mIconAnimator != null) { 87 mIconAnimator.cancel(); 88 } 89 return mIconAnimationProgress; 90 } 91 setDrawEnabled(boolean drawEnabled)92 public void setDrawEnabled(boolean drawEnabled) { 93 if (mDrawEnabled != drawEnabled) { 94 mDrawEnabled = drawEnabled; 95 invalidateSelf(); 96 } 97 } 98 99 @Override draw(Canvas canvas)100 public void draw(Canvas canvas) { 101 if (mCurrentRect != null && mDrawEnabled) { 102 canvas.drawRoundRect(mCurrentRect, mCornerRadius, mCornerRadius, mPaint); 103 if (mIcon != null && mIconAnimationProgress > 0f) { 104 canvas.save(); 105 float scale = Interpolators.clampToProgress(FAST_OUT_SLOW_IN, 0f, 106 1f).getInterpolation(mIconAnimationProgress); 107 canvas.translate(mCurrentRect.centerX() - mIcon.getBounds().width() / 2 * scale, 108 mCurrentRect.top - mIcon.getBounds().height() / 2 * scale); 109 canvas.scale(scale, scale); 110 mIcon.draw(canvas); 111 canvas.restore(); 112 } 113 } 114 } 115 116 @Override setAlpha(int i)117 public void setAlpha(int i) { } 118 119 @Override setColorFilter(ColorFilter colorFilter)120 public void setColorFilter(ColorFilter colorFilter) { } 121 122 @Override getOpacity()123 public int getOpacity() { 124 return PixelFormat.TRANSLUCENT; 125 } 126 setIconAnimationProgress(float progress)127 private void setIconAnimationProgress(float progress) { 128 mIconAnimationProgress = progress; 129 invalidateSelf(); 130 } 131 } 132