OLD | NEW |
---|---|
(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.appmenu; | |
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.annotation.ColorRes; | |
18 import android.view.animation.Interpolator; | |
19 | |
20 import org.chromium.base.ApiCompatibilityUtils; | |
21 | |
22 /** | |
23 * A custom {@link Drawable} that will animate a pulse using the {@link PulseInt erpolator}. Meant | |
24 * to be created with a {@link PulseDrawable#Painter} that does the actual drawi ng work based on | |
25 * the pulse interpolation value. | |
26 */ | |
27 public class PulseDrawable extends Drawable implements Animatable { | |
28 private static final long PULSE_DURATION_MS = 2500; | |
29 private static final long FRAME_RATE = 60; | |
30 | |
31 /** | |
32 * An interface that does the actual drawing work for this {@link Drawable}. Not meant to be | |
33 * stateful, as this could be shared across multiple instances of this drawa ble if it gets | |
34 * copied or mutated. | |
35 */ | |
36 public interface Painter { | |
37 /** | |
38 * Called when this drawable updates it's pulse interpolation. Should m utate the drawable | |
39 * as necessary. This is responsible for invalidating this {@link Drawa ble} if something | |
40 * needs to be redrawn. | |
41 * | |
42 * @param drawable The {@link PulseDrawable} that is updated. | |
43 * @param interpolation The current progress of whatever is being pulsed . | |
44 */ | |
45 void modifyDrawable(PulseDrawable drawable, float interpolation); | |
46 | |
47 /** | |
48 * Called when this {@link PulseDrawable} needs to draw. Should perform any draw operation | |
49 * for the specific type of pulse. | |
50 * @param drawable The calling {@link PulseDrawable}. | |
51 * @param paint A {@link Paint} object to use. This will automa tically have the | |
52 * color set. | |
53 * @param canvas The {@link Canvas} to draw to. | |
54 * @param interpolation The current progress of whatever is being pulsed . | |
55 */ | |
56 void draw(PulseDrawable drawable, Paint paint, Canvas canvas, float inte rpolation); | |
57 } | |
58 | |
59 private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); | |
60 private final Rect mInset = new Rect(); | |
61 private final Rect mOriginalBounds = new Rect(); | |
62 private final Rect mInsetBounds = new Rect(); | |
63 | |
64 protected PulseState mState; | |
Ted C
2017/04/12 18:05:57
why protected?
David Trainor- moved to gerrit
2017/04/12 18:59:37
Ah I was planning on overriding this class for the
| |
65 private boolean mMutated; | |
66 private boolean mRunning; | |
67 | |
68 /** | |
69 * Creates a new {@link PulseDrawable} instance. | |
70 * @param res A {@link Resources} object used to load the {@link Dr awable} parameters. | |
71 * @param color A color resource. | |
72 * @param interpolator An {@link Interpolator} that defines how the pulse wi ll fade in and out. | |
73 * @param painter The {@link Painter} that will be responsible for draw ing the pulse. | |
74 */ | |
75 public PulseDrawable( | |
76 Resources res, @ColorRes int color, Interpolator interpolator, Paint er painter) { | |
77 this(new PulseState(res, color, interpolator, painter)); | |
78 } | |
79 | |
80 private PulseDrawable(PulseState state) { | |
81 mState = state; | |
82 } | |
83 | |
84 /** What color to set the pulse to. */ | |
85 public void setColor(@ColorInt int color) { | |
Ted C
2017/04/12 18:05:57
I'd rather this not be configurable right now. I'
David Trainor- moved to gerrit
2017/04/12 18:59:37
I can have it set light/dark if you'd like. We on
| |
86 int alpha = getAlpha(); | |
87 mState.color = mState.drawColor = color; | |
88 setAlpha(alpha); | |
89 invalidateSelf(); | |
90 } | |
91 | |
92 /** How much to inset the bounds of this {@link Drawable} by. */ | |
93 public void setInset(int left, int top, int right, int bottom) { | |
94 mInset.set(left, top, right, bottom); | |
95 setBounds(mOriginalBounds); | |
Ted C
2017/04/12 18:05:57
Should we only call this if !mOriginalBounds.isEmp
David Trainor- moved to gerrit
2017/04/12 18:59:37
Yes good point.
| |
96 } | |
97 | |
98 // Animatable implementation. | |
99 @Override | |
100 public void start() { | |
101 if (mRunning) { | |
102 unscheduleSelf(mNextFrame); | |
103 scheduleSelf(mNextFrame, SystemClock.uptimeMillis() + 1000 / FRAME_R ATE); | |
104 } else { | |
105 mRunning = true; | |
106 if (mState.startTime == 0) mState.startTime = SystemClock.uptimeMill is(); | |
107 mNextFrame.run(); | |
108 } | |
109 } | |
110 | |
111 @Override | |
112 public void stop() { | |
113 mRunning = false; | |
114 mState.startTime = 0; | |
115 unscheduleSelf(mNextFrame); | |
116 } | |
117 | |
118 @Override | |
119 public boolean isRunning() { | |
120 return mRunning; | |
121 } | |
122 | |
123 // Drawable implementation. | |
124 // Overriding only this method because {@link Drawable#setBounds(Rect)} call s into this. | |
125 @Override | |
126 public void setBounds(int left, int top, int right, int bottom) { | |
127 mOriginalBounds.set(left, top, right, bottom); | |
128 mInsetBounds.set( | |
129 left + mInset.left, top + mInset.top, right - mInset.right, bott om - mInset.bottom); | |
130 super.setBounds( | |
131 mInsetBounds.left, mInsetBounds.top, mInsetBounds.right, mInsetB ounds.bottom); | |
132 } | |
133 | |
134 @Override | |
135 public void draw(Canvas canvas) { | |
136 mPaint.setColor(mState.drawColor); | |
137 mState.painter.draw(this, mPaint, canvas, mState.progress); | |
138 } | |
139 | |
140 @Override | |
141 public void setAlpha(int alpha) { | |
142 // Encode the alpha into the color. | |
143 alpha += alpha >> 7; // make it 0..256 | |
144 final int baseAlpha = mState.color >>> 24; | |
145 final int useAlpha = baseAlpha * alpha >> 8; | |
146 final int useColor = (mState.color << 8 >>> 8) | (useAlpha << 24); | |
147 if (mState.drawColor != useColor) { | |
148 mState.drawColor = useColor; | |
149 invalidateSelf(); | |
150 } | |
151 } | |
152 | |
153 @Override | |
154 public int getAlpha() { | |
155 return mState.drawColor >>> 24; | |
156 } | |
157 | |
158 @Override | |
159 public void setColorFilter(ColorFilter colorFilter) { | |
160 mPaint.setColorFilter(colorFilter); | |
161 } | |
162 | |
163 @Override | |
164 public int getOpacity() { | |
165 return PixelFormat.TRANSLUCENT; | |
166 } | |
167 | |
168 @Override | |
169 public boolean setVisible(boolean visible, boolean restart) { | |
170 final boolean changed = super.setVisible(visible, restart); | |
171 if (visible) { | |
172 if (changed || restart) start(); | |
173 } else { | |
174 stop(); | |
175 } | |
176 return changed; | |
177 } | |
178 | |
179 @Override | |
180 public Drawable mutate() { | |
181 if (!mMutated && super.mutate() == this) { | |
182 mState = new PulseState(mState); | |
183 mMutated = true; | |
184 } | |
185 return this; | |
186 } | |
187 | |
188 @Override | |
189 public ConstantState getConstantState() { | |
190 return mState; | |
191 } | |
192 | |
193 private void stepPulse() { | |
194 long curTime = SystemClock.uptimeMillis(); | |
195 long msIntoAnim = (curTime - mState.startTime) % PULSE_DURATION_MS; | |
196 float progress = ((float) msIntoAnim) / ((float) PULSE_DURATION_MS); | |
197 mState.progress = mState.interpolator.getInterpolation(progress); | |
198 mState.painter.modifyDrawable(PulseDrawable.this, mState.progress); | |
199 } | |
200 | |
201 /** | |
202 * The {@link ConstantState} subclass for this {@link PulseDrawable}. | |
203 */ | |
204 private static final class PulseState extends ConstantState { | |
205 // Current Paint State. | |
206 /** The current color, including alpha, to draw. */ | |
207 public int drawColor; | |
208 | |
209 /** The original color to draw (may not include any alpha updates. */ | |
Ted C
2017/04/12 18:05:57
may not, or does not? also missing trailing )
I
David Trainor- moved to gerrit
2017/04/12 18:59:37
It depends on whether or not the color passed in h
| |
210 public int color; | |
211 | |
212 // Current Animation State | |
213 /** The time from {@link SystemClock#updateMillis()} that this animation started at. */ | |
214 public long startTime; | |
215 | |
216 /** The current progress from 0 to 1 of the pulse. */ | |
217 public float progress; | |
218 | |
219 /** The {@link Interpolator} that makes the pulse and generates the prog ress. */ | |
220 public Interpolator interpolator; | |
221 | |
222 /** | |
223 * The {@link Painter} object that is responsible for modifying and draw ing this | |
224 * {@link PulseDrawable}. | |
225 */ | |
226 public Painter painter; | |
227 | |
228 PulseState(Resources res, @ColorRes int color, Interpolator interpolator , Painter painter) { | |
229 this.color = this.drawColor = ApiCompatibilityUtils.getColor(res, co lor); | |
230 | |
231 this.interpolator = new PulseInterpolator(interpolator); | |
232 this.painter = painter; | |
233 } | |
234 | |
235 PulseState(PulseState other) { | |
236 drawColor = other.drawColor; | |
237 color = other.color; | |
238 | |
239 startTime = other.startTime; | |
240 | |
241 interpolator = other.interpolator; | |
242 painter = other.painter; | |
243 } | |
244 | |
245 @Override | |
246 public Drawable newDrawable() { | |
247 return new PulseDrawable(this); | |
248 } | |
249 | |
250 @Override | |
251 public int getChangingConfigurations() { | |
252 return 0; | |
253 } | |
254 } | |
255 | |
256 private final Runnable mNextFrame = new Runnable() { | |
Ted C
2017/04/12 18:05:57
I'd put this above the constructor as it is a loca
David Trainor- moved to gerrit
2017/04/12 18:59:37
Done.
| |
257 @Override | |
258 public void run() { | |
259 stepPulse(); | |
260 if (mRunning) scheduleSelf(mNextFrame, SystemClock.uptimeMillis() + 1000 / FRAME_RATE); | |
261 } | |
262 }; | |
263 } | |
OLD | NEW |