Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(159)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/widget/PulseDrawable.java

Issue 2779543005: Add support for highlighting menu items (Closed)
Patch Set: Moved PulseDrawable Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.chrome.browser.widget;
6
7 import android.content.res.Resources;
8 import android.graphics.Canvas;
9 import android.graphics.ColorFilter;
10 import android.graphics.Paint;
11 import android.graphics.PixelFormat;
12 import android.graphics.Rect;
13 import android.graphics.drawable.Animatable;
14 import android.graphics.drawable.Drawable;
15 import android.os.SystemClock;
16 import android.support.annotation.ColorInt;
17 import android.support.v4.view.animation.FastOutSlowInInterpolator;
18 import android.support.v4.view.animation.PathInterpolatorCompat;
19 import android.view.animation.Interpolator;
20
21 import org.chromium.base.ApiCompatibilityUtils;
22 import org.chromium.base.ContextUtils;
23 import org.chromium.chrome.R;
24 import org.chromium.chrome.browser.util.MathUtils;
25
26 /**
27 * A custom {@link Drawable} that will animate a pulse using the {@link PulseInt erpolator}. Meant
28 * to be created with a {@link PulseDrawable#Painter} that does the actual drawi ng work based on
29 * the pulse interpolation value.
30 */
31 public class PulseDrawable extends Drawable implements Animatable {
32 private static final long PULSE_DURATION_MS = 2500;
33 private static final long FRAME_RATE = 60;
34
35 /**
36 * An interface that does the actual drawing work for this {@link Drawable}. Not meant to be
37 * stateful, as this could be shared across multiple instances of this drawa ble if it gets
38 * copied or mutated.
39 */
40 private interface Painter {
41 /**
42 * Called when this drawable updates it's pulse interpolation. Should m utate the drawable
43 * as necessary. This is responsible for invalidating this {@link Drawa ble} if something
44 * needs to be redrawn.
45 *
46 * @param drawable The {@link PulseDrawable} that is updated.
47 * @param interpolation The current progress of whatever is being pulsed .
48 */
49 void modifyDrawable(PulseDrawable drawable, float interpolation);
50
51 /**
52 * Called when this {@link PulseDrawable} needs to draw. Should perform any draw operation
53 * for the specific type of pulse.
54 * @param drawable The calling {@link PulseDrawable}.
55 * @param paint A {@link Paint} object to use. This will automa tically have the
56 * color set.
57 * @param canvas The {@link Canvas} to draw to.
58 * @param interpolation The current progress of whatever is being pulsed .
59 */
60 void draw(PulseDrawable drawable, Paint paint, Canvas canvas, float inte rpolation);
61 }
62
63 /**
64 * Creates a {@link PulseDrawable} that will fill the bounds with a pulsing color.
65 * @return A new {@link PulseDrawable} instance.
66 */
67 public static PulseDrawable createHighlight() {
68 PulseDrawable.Painter painter = new PulseDrawable.Painter() {
69 @Override
70 public void modifyDrawable(PulseDrawable drawable, float interpolati on) {
71 drawable.setAlpha((int) MathUtils.interpolate(12, 75, interpolat ion));
72 }
73
74 @Override
75 public void draw(
76 PulseDrawable drawable, Paint paint, Canvas canvas, float in terpolation) {
77 canvas.drawRect(drawable.getBounds(), paint);
78 }
79 };
80
81 return new PulseDrawable(new FastOutSlowInInterpolator(), painter);
82 }
83
84 /**
85 * Creates a {@link PulseDrawable} that will draw a pulsing circle inside th e bounds.
86 * @return A new {@link PulseDrawable} instance.
87 */
88 public static PulseDrawable createCircle() {
89 PulseDrawable.Painter painter = new PulseDrawable.Painter() {
90 @Override
91 public void modifyDrawable(PulseDrawable drawable, float interpolati on) {
92 drawable.invalidateSelf();
93 }
94
95 @Override
96 public void draw(
97 PulseDrawable drawable, Paint paint, Canvas canvas, float in terpolation) {
98 Rect bounds = drawable.getBounds();
99 float scale = MathUtils.interpolate(0.8f, 1.f, interpolation);
100 float radius = Math.min(bounds.width(), bounds.height()) * scale / 2.f;
101 canvas.drawCircle(bounds.exactCenterX(), bounds.exactCenterY(), radius, paint);
102 }
103 };
104
105 PulseDrawable drawable =
106 new PulseDrawable(PathInterpolatorCompat.create(.8f, 0.f, .6f, 1 .f), painter);
107 drawable.setAlpha(76);
108 return drawable;
109 }
110
111 private final Runnable mNextFrame = new Runnable() {
112 @Override
113 public void run() {
114 stepPulse();
115 if (mRunning) scheduleSelf(mNextFrame, SystemClock.uptimeMillis() + 1000 / FRAME_RATE);
116 }
117 };
118
119 private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
120 private final Rect mInset = new Rect();
121 private final Rect mOriginalBounds = new Rect();
122 private final Rect mInsetBounds = new Rect();
123
124 private PulseState mState;
125 private boolean mMutated;
126 private boolean mRunning;
127
128 /**
129 * Creates a new {@link PulseDrawable} instance.
130 * @param interpolator An {@link Interpolator} that defines how the pulse wi ll fade in and out.
131 * @param painter The {@link Painter} that will be responsible for draw ing the pulse.
132 */
133 private PulseDrawable(Interpolator interpolator, Painter painter) {
134 this(new PulseState(interpolator, painter));
135 setUseLightPulseColor(false);
136 }
137
138 private PulseDrawable(PulseState state) {
139 mState = state;
140 }
141
142 /** Whether or not to use a light or dark color for the pulse. */
143 public void setUseLightPulseColor(boolean useLightPulseColor) {
144 Resources resources = ContextUtils.getApplicationContext().getResources( );
145
146 @ColorInt
147 int color = ApiCompatibilityUtils.getColor(
148 resources, useLightPulseColor ? R.color.google_grey_100 : R.colo r.google_blue_500);
149 if (mState.color == color) return;
150
151 int alpha = getAlpha();
152 mState.color = mState.drawColor = color;
153 setAlpha(alpha);
154 invalidateSelf();
155 }
156
157 /** How much to inset the bounds of this {@link Drawable} by. */
158 public void setInset(int left, int top, int right, int bottom) {
159 mInset.set(left, top, right, bottom);
160 if (!mOriginalBounds.isEmpty()) setBounds(mOriginalBounds);
161 }
162
163 // Animatable implementation.
164 @Override
165 public void start() {
166 if (mRunning) {
167 unscheduleSelf(mNextFrame);
168 scheduleSelf(mNextFrame, SystemClock.uptimeMillis() + 1000 / FRAME_R ATE);
169 } else {
170 mRunning = true;
171 if (mState.startTime == 0) mState.startTime = SystemClock.uptimeMill is();
172 mNextFrame.run();
173 }
174 }
175
176 @Override
177 public void stop() {
178 mRunning = false;
179 mState.startTime = 0;
180 unscheduleSelf(mNextFrame);
181 }
182
183 @Override
184 public boolean isRunning() {
185 return mRunning;
186 }
187
188 // Drawable implementation.
189 // Overriding only this method because {@link Drawable#setBounds(Rect)} call s into this.
190 @Override
191 public void setBounds(int left, int top, int right, int bottom) {
192 mOriginalBounds.set(left, top, right, bottom);
193 mInsetBounds.set(
194 left + mInset.left, top + mInset.top, right - mInset.right, bott om - mInset.bottom);
195 super.setBounds(
196 mInsetBounds.left, mInsetBounds.top, mInsetBounds.right, mInsetB ounds.bottom);
197 }
198
199 @Override
200 public void draw(Canvas canvas) {
201 mPaint.setColor(mState.drawColor);
202 mState.painter.draw(this, mPaint, canvas, mState.progress);
203 }
204
205 @Override
206 public void setAlpha(int alpha) {
207 // Encode the alpha into the color.
208 alpha += alpha >> 7; // make it 0..256
209 final int baseAlpha = mState.color >>> 24;
210 final int useAlpha = baseAlpha * alpha >> 8;
211 final int useColor = (mState.color << 8 >>> 8) | (useAlpha << 24);
212 if (mState.drawColor != useColor) {
213 mState.drawColor = useColor;
214 invalidateSelf();
215 }
216 }
217
218 @Override
219 public int getAlpha() {
220 return mState.drawColor >>> 24;
221 }
222
223 @Override
224 public void setColorFilter(ColorFilter colorFilter) {
225 mPaint.setColorFilter(colorFilter);
226 }
227
228 @Override
229 public int getOpacity() {
230 return PixelFormat.TRANSLUCENT;
231 }
232
233 @Override
234 public boolean setVisible(boolean visible, boolean restart) {
235 final boolean changed = super.setVisible(visible, restart);
236 if (visible) {
237 if (changed || restart) start();
238 } else {
239 stop();
240 }
241 return changed;
242 }
243
244 @Override
245 public Drawable mutate() {
246 if (!mMutated && super.mutate() == this) {
247 mState = new PulseState(mState);
248 mMutated = true;
249 }
250 return this;
251 }
252
253 @Override
254 public ConstantState getConstantState() {
255 return mState;
256 }
257
258 private void stepPulse() {
259 long curTime = SystemClock.uptimeMillis();
260 long msIntoAnim = (curTime - mState.startTime) % PULSE_DURATION_MS;
261 float progress = ((float) msIntoAnim) / ((float) PULSE_DURATION_MS);
262 mState.progress = mState.interpolator.getInterpolation(progress);
263 mState.painter.modifyDrawable(PulseDrawable.this, mState.progress);
264 }
265
266 /**
267 * The {@link ConstantState} subclass for this {@link PulseDrawable}.
268 */
269 private static final class PulseState extends ConstantState {
270 // Current Paint State.
271 /** The current color, including alpha, to draw. */
272 public int drawColor;
273
274 /** The original color to draw (will not include updates from calls to s etAlpha()). */
275 public int color;
276
277 // Current Animation State
278 /** The time from {@link SystemClock#updateMillis()} that this animation started at. */
279 public long startTime;
280
281 /** The current progress from 0 to 1 of the pulse. */
282 public float progress;
283
284 /** The {@link Interpolator} that makes the pulse and generates the prog ress. */
285 public Interpolator interpolator;
286
287 /**
288 * The {@link Painter} object that is responsible for modifying and draw ing this
289 * {@link PulseDrawable}.
290 */
291 public Painter painter;
292
293 PulseState(Interpolator interpolator, Painter painter) {
294 this.interpolator = new PulseInterpolator(interpolator);
295 this.painter = painter;
296 }
297
298 PulseState(PulseState other) {
299 drawColor = other.drawColor;
300 color = other.color;
301
302 startTime = other.startTime;
303
304 interpolator = other.interpolator;
305 painter = other.painter;
306 }
307
308 @Override
309 public Drawable newDrawable() {
310 return new PulseDrawable(this);
311 }
312
313 @Override
314 public int getChangingConfigurations() {
315 return 0;
316 }
317 }
318 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698