Sunny Goyal | 3484638 | 2014-07-09 00:09:28 -0700 | [diff] [blame^] | 1 | package com.android.launcher3; |
| 2 | |
| 3 | import android.animation.ObjectAnimator; |
| 4 | import android.content.res.Resources; |
| 5 | import android.graphics.Bitmap; |
| 6 | import android.graphics.BitmapFactory; |
| 7 | import android.graphics.Canvas; |
| 8 | import android.graphics.ColorFilter; |
| 9 | import android.graphics.Paint; |
| 10 | import android.graphics.Path; |
| 11 | import android.graphics.PixelFormat; |
| 12 | import android.graphics.Rect; |
| 13 | import android.graphics.RectF; |
| 14 | import android.graphics.drawable.Drawable; |
| 15 | |
| 16 | class PreloadIconDrawable extends Drawable { |
| 17 | private static final float ANIMATION_PROGRESS_STOPPED = -1.0f; |
| 18 | private static final float ANIMATION_PROGRESS_STARTED = 0f; |
| 19 | private static final float ANIMATION_PROGRESS_COMPLETED = 1.0f; |
| 20 | |
| 21 | private static final float ICON_SCALE_FACTOR = 0.6f; |
| 22 | |
| 23 | private static Bitmap sProgressBg, sProgressFill; |
| 24 | |
| 25 | private final Rect mCanvasClipRect = new Rect(); |
| 26 | private final RectF mRect = new RectF(); |
| 27 | private final Path mProgressPath = new Path(); |
| 28 | private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG); |
| 29 | |
| 30 | final Drawable mIcon; |
| 31 | |
| 32 | /** |
| 33 | * Indicates the progress of the preloader [0-100]. If it goes above 100, only the icon |
| 34 | * is shown with no progress bar. |
| 35 | */ |
| 36 | private int mProgress = 0; |
| 37 | private boolean mPathChanged; |
| 38 | |
| 39 | private float mAnimationProgress = ANIMATION_PROGRESS_STOPPED; |
| 40 | private ObjectAnimator mAnimator; |
| 41 | |
| 42 | public PreloadIconDrawable(Drawable icon, Resources res) { |
| 43 | mIcon = icon; |
| 44 | |
| 45 | setBounds(icon.getBounds()); |
| 46 | mPathChanged = false; |
| 47 | |
| 48 | if (sProgressBg == null) { |
| 49 | sProgressBg = BitmapFactory.decodeResource(res, R.drawable.bg_preloader); |
| 50 | } |
| 51 | if (sProgressFill == null) { |
| 52 | sProgressFill = BitmapFactory.decodeResource(res, R.drawable.bg_preloader_progress); |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | @Override |
| 57 | public void draw(Canvas canvas) { |
| 58 | final Rect r = getBounds(); |
| 59 | if (canvas.getClipBounds(mCanvasClipRect) && !Rect.intersects(mCanvasClipRect, r)) { |
| 60 | // The draw region has been clipped. |
| 61 | return; |
| 62 | } |
| 63 | final float iconScale; |
| 64 | |
| 65 | if ((mAnimationProgress >= ANIMATION_PROGRESS_STARTED) |
| 66 | && (mAnimationProgress < ANIMATION_PROGRESS_COMPLETED)) { |
| 67 | mPaint.setAlpha((int) ((1 - mAnimationProgress) * 255)); |
| 68 | canvas.drawBitmap(sProgressBg, null, r, mPaint); |
| 69 | canvas.drawBitmap(sProgressFill, null, r, mPaint); |
| 70 | iconScale = ICON_SCALE_FACTOR + (1 - ICON_SCALE_FACTOR) * mAnimationProgress; |
| 71 | |
| 72 | } else if (mAnimationProgress == ANIMATION_PROGRESS_STOPPED) { |
| 73 | mPaint.setAlpha(255); |
| 74 | iconScale = ICON_SCALE_FACTOR; |
| 75 | canvas.drawBitmap(sProgressBg, null, r, mPaint); |
| 76 | |
| 77 | if (mProgress >= 100) { |
| 78 | canvas.drawBitmap(sProgressFill, null, r, mPaint); |
| 79 | } else if (mProgress > 0) { |
| 80 | if (mPathChanged) { |
| 81 | mProgressPath.reset(); |
| 82 | mProgressPath.moveTo(r.exactCenterX(), r.centerY()); |
| 83 | |
| 84 | mRect.set(r); |
| 85 | mProgressPath.arcTo(mRect, -90, mProgress * 3.6f); |
| 86 | mProgressPath.close(); |
| 87 | mPathChanged = false; |
| 88 | } |
| 89 | |
| 90 | canvas.save(); |
| 91 | canvas.clipPath(mProgressPath); |
| 92 | canvas.drawBitmap(sProgressFill, null, r, mPaint); |
| 93 | canvas.restore(); |
| 94 | } |
| 95 | } else { |
| 96 | iconScale = 1; |
| 97 | } |
| 98 | |
| 99 | canvas.save(); |
| 100 | canvas.scale(iconScale, iconScale, r.exactCenterX(), r.exactCenterY()); |
| 101 | mIcon.draw(canvas); |
| 102 | canvas.restore(); |
| 103 | } |
| 104 | |
| 105 | @Override |
| 106 | protected void onBoundsChange(Rect bounds) { |
| 107 | mIcon.setBounds(bounds); |
| 108 | mPathChanged = true; |
| 109 | } |
| 110 | |
| 111 | @Override |
| 112 | public int getOpacity() { |
| 113 | return PixelFormat.TRANSLUCENT; |
| 114 | } |
| 115 | |
| 116 | @Override |
| 117 | public void setAlpha(int alpha) { |
| 118 | mIcon.setAlpha(alpha); |
| 119 | } |
| 120 | |
| 121 | @Override |
| 122 | public void setColorFilter(ColorFilter cf) { |
| 123 | mIcon.setColorFilter(cf); |
| 124 | } |
| 125 | |
| 126 | @Override |
| 127 | protected boolean onLevelChange(int level) { |
| 128 | mProgress = level; |
| 129 | mPathChanged = true; |
| 130 | |
| 131 | // Stop Animation |
| 132 | if (mAnimator != null) { |
| 133 | mAnimator.cancel(); |
| 134 | mAnimator = null; |
| 135 | } |
| 136 | mAnimationProgress = ANIMATION_PROGRESS_STOPPED; |
| 137 | |
| 138 | invalidateSelf(); |
| 139 | return true; |
| 140 | } |
| 141 | |
| 142 | /** |
| 143 | * Runs the finish animation if it is has not been run after last level change. |
| 144 | */ |
| 145 | public void maybePerformFinishedAnimation() { |
| 146 | if (mAnimationProgress > ANIMATION_PROGRESS_STOPPED) { |
| 147 | return; |
| 148 | } |
| 149 | if (mAnimator != null) { |
| 150 | mAnimator.cancel(); |
| 151 | } |
| 152 | setAnimationProgress(ANIMATION_PROGRESS_STARTED); |
| 153 | mAnimator = ObjectAnimator.ofFloat(this, "animationProgress", |
| 154 | ANIMATION_PROGRESS_STARTED, ANIMATION_PROGRESS_COMPLETED); |
| 155 | mAnimator.start(); |
| 156 | } |
| 157 | |
| 158 | public void setAnimationProgress(float progress) { |
| 159 | if (progress != mAnimationProgress) { |
| 160 | mAnimationProgress = progress; |
| 161 | invalidateSelf(); |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | public float getAnimationProgress() { |
| 166 | return mAnimationProgress; |
| 167 | } |
| 168 | } |