Chromium Code Reviews| 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 |