blob: b064c47fc72389f995d59fb758b97f3dbb460bea [file] [log] [blame]
Sunny Goyal34846382014-07-09 00:09:28 -07001package com.android.launcher3;
2
3import android.animation.ObjectAnimator;
Sunny Goyal95abbb32014-08-04 10:53:22 -07004import android.content.res.Resources.Theme;
5import android.content.res.TypedArray;
Sunny Goyal34846382014-07-09 00:09:28 -07006import android.graphics.Canvas;
Sunny Goyal95abbb32014-08-04 10:53:22 -07007import android.graphics.Color;
Sunny Goyal34846382014-07-09 00:09:28 -07008import android.graphics.ColorFilter;
9import android.graphics.Paint;
Sunny Goyal34846382014-07-09 00:09:28 -070010import android.graphics.PixelFormat;
11import android.graphics.Rect;
12import android.graphics.RectF;
13import android.graphics.drawable.Drawable;
14
Adam Cohenf9c184a2016-01-15 16:47:43 -080015public class PreloadIconDrawable extends Drawable {
Sunny Goyal95abbb32014-08-04 10:53:22 -070016
Sunny Goyal34846382014-07-09 00:09:28 -070017 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
Sunny Goyal95abbb32014-08-04 10:53:22 -070021 private static final float MIN_SATUNATION = 0.2f;
22 private static final float MIN_LIGHTNESS = 0.6f;
Sunny Goyal34846382014-07-09 00:09:28 -070023
Sunny Goyal95abbb32014-08-04 10:53:22 -070024 private static final float ICON_SCALE_FACTOR = 0.5f;
25 private static final int DEFAULT_COLOR = 0xFF009688;
Sunny Goyal34846382014-07-09 00:09:28 -070026
Sunny Goyal95abbb32014-08-04 10:53:22 -070027 private static final Rect sTempRect = new Rect();
Sunny Goyal34846382014-07-09 00:09:28 -070028
Sunny Goyal95abbb32014-08-04 10:53:22 -070029 private final RectF mIndicatorRect = new RectF();
30 private boolean mIndicatorRectDirty;
31
32 private final Paint mPaint;
Adam Cohenf9c184a2016-01-15 16:47:43 -080033 public final Drawable mIcon;
Sunny Goyal34846382014-07-09 00:09:28 -070034
Sunny Goyal95abbb32014-08-04 10:53:22 -070035 private Drawable mBgDrawable;
36 private int mRingOutset;
37
38 private int mIndicatorColor = 0;
39
Sunny Goyal34846382014-07-09 00:09:28 -070040 /**
41 * Indicates the progress of the preloader [0-100]. If it goes above 100, only the icon
42 * is shown with no progress bar.
43 */
44 private int mProgress = 0;
Sunny Goyal34846382014-07-09 00:09:28 -070045
46 private float mAnimationProgress = ANIMATION_PROGRESS_STOPPED;
47 private ObjectAnimator mAnimator;
48
Sunny Goyal95abbb32014-08-04 10:53:22 -070049 public PreloadIconDrawable(Drawable icon, Theme theme) {
Sunny Goyal34846382014-07-09 00:09:28 -070050 mIcon = icon;
51
Sunny Goyal95abbb32014-08-04 10:53:22 -070052 mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
53 mPaint.setStyle(Paint.Style.STROKE);
54 mPaint.setStrokeCap(Paint.Cap.ROUND);
Sunny Goyal34846382014-07-09 00:09:28 -070055
Sunny Goyal95abbb32014-08-04 10:53:22 -070056 setBounds(icon.getBounds());
Sunny Goyal71b5c0b2015-01-08 16:59:04 -080057 applyPreloaderTheme(theme);
Sunny Goyal95abbb32014-08-04 10:53:22 -070058 onLevelChange(0);
59 }
60
Sunny Goyal71b5c0b2015-01-08 16:59:04 -080061 public void applyPreloaderTheme(Theme t) {
Sunny Goyal95abbb32014-08-04 10:53:22 -070062 TypedArray ta = t.obtainStyledAttributes(R.styleable.PreloadIconDrawable);
Sunny Goyal59871ef2016-02-24 00:27:08 +000063 mBgDrawable = ta.getDrawable(R.styleable.PreloadIconDrawable_background);
Sunny Goyal95abbb32014-08-04 10:53:22 -070064 mBgDrawable.setFilterBitmap(true);
65 mPaint.setStrokeWidth(ta.getDimension(R.styleable.PreloadIconDrawable_indicatorSize, 0));
66 mRingOutset = ta.getDimensionPixelSize(R.styleable.PreloadIconDrawable_ringOutset, 0);
67 ta.recycle();
68 onBoundsChange(getBounds());
69 invalidateSelf();
70 }
71
72 @Override
73 protected void onBoundsChange(Rect bounds) {
74 mIcon.setBounds(bounds);
75 if (mBgDrawable != null) {
76 sTempRect.set(bounds);
77 sTempRect.inset(-mRingOutset, -mRingOutset);
78 mBgDrawable.setBounds(sTempRect);
Sunny Goyal34846382014-07-09 00:09:28 -070079 }
Sunny Goyal95abbb32014-08-04 10:53:22 -070080 mIndicatorRectDirty = true;
81 }
82
83 public int getOutset() {
84 return mRingOutset;
85 }
86
87 /**
88 * The size of the indicator is same as the content region of the {@link #mBgDrawable} minus
89 * half the stroke size to accommodate the indicator.
90 */
91 private void initIndicatorRect() {
92 Drawable d = mBgDrawable;
93 Rect bounds = d.getBounds();
94
95 d.getPadding(sTempRect);
96 // Amount by which padding has to be scaled
97 float paddingScaleX = ((float) bounds.width()) / d.getIntrinsicWidth();
98 float paddingScaleY = ((float) bounds.height()) / d.getIntrinsicHeight();
99 mIndicatorRect.set(
100 bounds.left + sTempRect.left * paddingScaleX,
101 bounds.top + sTempRect.top * paddingScaleY,
102 bounds.right - sTempRect.right * paddingScaleX,
103 bounds.bottom - sTempRect.bottom * paddingScaleY);
104
105 float inset = mPaint.getStrokeWidth() / 2;
106 mIndicatorRect.inset(inset, inset);
107 mIndicatorRectDirty = false;
Sunny Goyal34846382014-07-09 00:09:28 -0700108 }
109
110 @Override
111 public void draw(Canvas canvas) {
Sunny Goyal95abbb32014-08-04 10:53:22 -0700112 final Rect r = new Rect(getBounds());
113 if (canvas.getClipBounds(sTempRect) && !Rect.intersects(sTempRect, r)) {
Sunny Goyal34846382014-07-09 00:09:28 -0700114 // The draw region has been clipped.
115 return;
116 }
Sunny Goyal95abbb32014-08-04 10:53:22 -0700117 if (mIndicatorRectDirty) {
118 initIndicatorRect();
119 }
Sunny Goyal34846382014-07-09 00:09:28 -0700120 final float iconScale;
121
122 if ((mAnimationProgress >= ANIMATION_PROGRESS_STARTED)
123 && (mAnimationProgress < ANIMATION_PROGRESS_COMPLETED)) {
124 mPaint.setAlpha((int) ((1 - mAnimationProgress) * 255));
Sunny Goyal95abbb32014-08-04 10:53:22 -0700125 mBgDrawable.setAlpha(mPaint.getAlpha());
126 mBgDrawable.draw(canvas);
127 canvas.drawOval(mIndicatorRect, mPaint);
Sunny Goyal34846382014-07-09 00:09:28 -0700128
Sunny Goyal95abbb32014-08-04 10:53:22 -0700129 iconScale = ICON_SCALE_FACTOR + (1 - ICON_SCALE_FACTOR) * mAnimationProgress;
Sunny Goyal34846382014-07-09 00:09:28 -0700130 } else if (mAnimationProgress == ANIMATION_PROGRESS_STOPPED) {
131 mPaint.setAlpha(255);
132 iconScale = ICON_SCALE_FACTOR;
Sunny Goyal95abbb32014-08-04 10:53:22 -0700133 mBgDrawable.setAlpha(255);
134 mBgDrawable.draw(canvas);
Sunny Goyal34846382014-07-09 00:09:28 -0700135
136 if (mProgress >= 100) {
Sunny Goyal95abbb32014-08-04 10:53:22 -0700137 canvas.drawOval(mIndicatorRect, mPaint);
Sunny Goyal34846382014-07-09 00:09:28 -0700138 } else if (mProgress > 0) {
Sunny Goyal95abbb32014-08-04 10:53:22 -0700139 canvas.drawArc(mIndicatorRect, -90, mProgress * 3.6f, false, mPaint);
Sunny Goyal34846382014-07-09 00:09:28 -0700140 }
141 } else {
142 iconScale = 1;
143 }
144
145 canvas.save();
146 canvas.scale(iconScale, iconScale, r.exactCenterX(), r.exactCenterY());
147 mIcon.draw(canvas);
148 canvas.restore();
149 }
150
151 @Override
Sunny Goyal34846382014-07-09 00:09:28 -0700152 public int getOpacity() {
153 return PixelFormat.TRANSLUCENT;
154 }
155
156 @Override
157 public void setAlpha(int alpha) {
158 mIcon.setAlpha(alpha);
159 }
160
161 @Override
162 public void setColorFilter(ColorFilter cf) {
163 mIcon.setColorFilter(cf);
164 }
165
166 @Override
167 protected boolean onLevelChange(int level) {
168 mProgress = level;
Sunny Goyal34846382014-07-09 00:09:28 -0700169
170 // Stop Animation
171 if (mAnimator != null) {
172 mAnimator.cancel();
173 mAnimator = null;
174 }
175 mAnimationProgress = ANIMATION_PROGRESS_STOPPED;
Sunny Goyal95abbb32014-08-04 10:53:22 -0700176 if (level > 0) {
177 // Set the paint color only when the level changes, so that the dominant color
178 // is only calculated when needed.
179 mPaint.setColor(getIndicatorColor());
180 }
181 if (mIcon instanceof FastBitmapDrawable) {
Winsonc0880492015-08-21 11:16:27 -0700182 ((FastBitmapDrawable) mIcon).setState(level <= 0 ?
183 FastBitmapDrawable.State.DISABLED : FastBitmapDrawable.State.NORMAL);
Sunny Goyal95abbb32014-08-04 10:53:22 -0700184 }
Sunny Goyal34846382014-07-09 00:09:28 -0700185
186 invalidateSelf();
187 return true;
188 }
189
190 /**
191 * Runs the finish animation if it is has not been run after last level change.
192 */
Sunny Goyal34942622014-08-29 17:20:55 -0700193 public void maybePerformFinishedAnimation() {
Sunny Goyal34846382014-07-09 00:09:28 -0700194 if (mAnimationProgress > ANIMATION_PROGRESS_STOPPED) {
Sunny Goyal34942622014-08-29 17:20:55 -0700195 return;
Sunny Goyal34846382014-07-09 00:09:28 -0700196 }
197 if (mAnimator != null) {
198 mAnimator.cancel();
199 }
200 setAnimationProgress(ANIMATION_PROGRESS_STARTED);
201 mAnimator = ObjectAnimator.ofFloat(this, "animationProgress",
202 ANIMATION_PROGRESS_STARTED, ANIMATION_PROGRESS_COMPLETED);
203 mAnimator.start();
204 }
205
206 public void setAnimationProgress(float progress) {
207 if (progress != mAnimationProgress) {
208 mAnimationProgress = progress;
209 invalidateSelf();
210 }
211 }
212
213 public float getAnimationProgress() {
214 return mAnimationProgress;
215 }
Sunny Goyal95abbb32014-08-04 10:53:22 -0700216
Sunny Goyal3fcab662015-08-11 15:17:30 -0700217 public boolean hasNotCompleted() {
218 return mAnimationProgress < ANIMATION_PROGRESS_COMPLETED;
219 }
220
Sunny Goyal95abbb32014-08-04 10:53:22 -0700221 @Override
222 public int getIntrinsicHeight() {
223 return mIcon.getIntrinsicHeight();
224 }
225
226 @Override
227 public int getIntrinsicWidth() {
228 return mIcon.getIntrinsicWidth();
229 }
230
231 private int getIndicatorColor() {
232 if (mIndicatorColor != 0) {
233 return mIndicatorColor;
234 }
235 if (!(mIcon instanceof FastBitmapDrawable)) {
236 mIndicatorColor = DEFAULT_COLOR;
237 return mIndicatorColor;
238 }
239 mIndicatorColor = Utilities.findDominantColorByHue(
240 ((FastBitmapDrawable) mIcon).getBitmap(), 20);
241
242 // Make sure that the dominant color has enough saturation to be visible properly.
243 float[] hsv = new float[3];
244 Color.colorToHSV(mIndicatorColor, hsv);
245 if (hsv[1] < MIN_SATUNATION) {
246 mIndicatorColor = DEFAULT_COLOR;
247 return mIndicatorColor;
248 }
249 hsv[2] = Math.max(MIN_LIGHTNESS, hsv[2]);
250 mIndicatorColor = Color.HSVToColor(hsv);
251 return mIndicatorColor;
252 }
Sunny Goyal34846382014-07-09 00:09:28 -0700253}