blob: d9365cc1fa8c46f331baa6c3c60c6eed1f9324db [file] [log] [blame]
Sunny Goyal34846382014-07-09 00:09:28 -07001package com.android.launcher3;
2
3import android.animation.ObjectAnimator;
4import android.content.res.Resources;
5import android.graphics.Bitmap;
6import android.graphics.BitmapFactory;
7import android.graphics.Canvas;
8import android.graphics.ColorFilter;
9import android.graphics.Paint;
10import android.graphics.Path;
11import android.graphics.PixelFormat;
12import android.graphics.Rect;
13import android.graphics.RectF;
14import android.graphics.drawable.Drawable;
15
16class 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}