blob: 86da67383a27d797d302f2e06d64c79529026f24 [file] [log] [blame]
Chet Haasea18a86b2010-09-07 13:20:00 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.animation;
18
Chet Haasea18a86b2010-09-07 13:20:00 -070019import android.os.Looper;
Romain Guy18772ea2013-04-10 18:31:22 -070020import android.os.Trace;
Chet Haase2970c492010-11-09 13:58:04 -080021import android.util.AndroidRuntimeException;
Jeff Brown96e942d2011-11-30 19:55:01 -080022import android.view.Choreographer;
Chet Haasea18a86b2010-09-07 13:20:00 -070023import android.view.animation.AccelerateDecelerateInterpolator;
24import android.view.animation.AnimationUtils;
Chet Haase27c1d4d2010-12-16 07:58:28 -080025import android.view.animation.LinearInterpolator;
Chet Haasea18a86b2010-09-07 13:20:00 -070026
27import java.util.ArrayList;
28import java.util.HashMap;
29
30/**
31 * This class provides a simple timing engine for running animations
32 * which calculate animated values and set them on target objects.
33 *
34 * <p>There is a single timing pulse that all animations use. It runs in a
35 * custom handler to ensure that property changes happen on the UI thread.</p>
36 *
37 * <p>By default, ValueAnimator uses non-linear time interpolation, via the
38 * {@link AccelerateDecelerateInterpolator} class, which accelerates into and decelerates
39 * out of an animation. This behavior can be changed by calling
Chet Haasee0ee2e92010-10-07 09:06:18 -070040 * {@link ValueAnimator#setInterpolator(TimeInterpolator)}.</p>
Joe Fernandez3aef8e1d2011-12-20 10:38:34 -080041 *
42 * <div class="special reference">
43 * <h3>Developer Guides</h3>
44 * <p>For more information about animating with {@code ValueAnimator}, read the
45 * <a href="{@docRoot}guide/topics/graphics/prop-animation.html#value-animator">Property
46 * Animation</a> developer guide.</p>
47 * </div>
Chet Haasea18a86b2010-09-07 13:20:00 -070048 */
Romain Guy18772ea2013-04-10 18:31:22 -070049@SuppressWarnings("unchecked")
Chet Haase2794eb32010-10-12 16:29:28 -070050public class ValueAnimator extends Animator {
Chet Haasea18a86b2010-09-07 13:20:00 -070051
52 /**
53 * Internal constants
54 */
Chet Haased21a9fe2012-02-01 14:14:17 -080055 private static float sDurationScale = 1.0f;
Chet Haasea18a86b2010-09-07 13:20:00 -070056
Chet Haasea18a86b2010-09-07 13:20:00 -070057 /**
Chet Haasea18a86b2010-09-07 13:20:00 -070058 * Values used with internal variable mPlayingState to indicate the current state of an
59 * animation.
60 */
Chet Haase051d35e2010-12-14 07:20:58 -080061 static final int STOPPED = 0; // Not yet playing
62 static final int RUNNING = 1; // Playing normally
63 static final int SEEKED = 2; // Seeked to some time value
Chet Haasea18a86b2010-09-07 13:20:00 -070064
65 /**
66 * Internal variables
67 * NOTE: This object implements the clone() method, making a deep copy of any referenced
68 * objects. As other non-trivial fields are added to this class, make sure to add logic
69 * to clone() to make deep copies of them.
70 */
71
72 // The first time that the animation's animateFrame() method is called. This time is used to
73 // determine elapsed time (and therefore the elapsed fraction) in subsequent calls
74 // to animateFrame()
Chet Haase051d35e2010-12-14 07:20:58 -080075 long mStartTime;
Chet Haasea18a86b2010-09-07 13:20:00 -070076
77 /**
78 * Set when setCurrentPlayTime() is called. If negative, animation is not currently seeked
79 * to a value.
80 */
Chet Haase051d35e2010-12-14 07:20:58 -080081 long mSeekTime = -1;
Chet Haasea18a86b2010-09-07 13:20:00 -070082
Chet Haase8aa1ffb2013-08-08 14:00:00 -070083 /**
84 * Set on the next frame after pause() is called, used to calculate a new startTime
85 * or delayStartTime which allows the animator to continue from the point at which
86 * it was paused. If negative, has not yet been set.
87 */
88 private long mPauseTime;
89
90 /**
91 * Set when an animator is resumed. This triggers logic in the next frame which
92 * actually resumes the animator.
93 */
94 private boolean mResumed = false;
95
96
Chet Haasea18a86b2010-09-07 13:20:00 -070097 // The static sAnimationHandler processes the internal timing loop on which all animations
98 // are based
Chet Haasebe19e032013-03-15 17:08:55 -070099 /**
100 * @hide
101 */
102 protected static ThreadLocal<AnimationHandler> sAnimationHandler =
Chet Haasee3bc4e62010-10-27 13:18:54 -0700103 new ThreadLocal<AnimationHandler>();
Chet Haasea18a86b2010-09-07 13:20:00 -0700104
Chet Haasea18a86b2010-09-07 13:20:00 -0700105 // The time interpolator to be used if none is set on the animation
Chet Haasee0ee2e92010-10-07 09:06:18 -0700106 private static final TimeInterpolator sDefaultInterpolator =
107 new AccelerateDecelerateInterpolator();
Chet Haasea18a86b2010-09-07 13:20:00 -0700108
Chet Haasea18a86b2010-09-07 13:20:00 -0700109 /**
110 * Used to indicate whether the animation is currently playing in reverse. This causes the
111 * elapsed fraction to be inverted to calculate the appropriate values.
112 */
113 private boolean mPlayingBackwards = false;
114
115 /**
116 * This variable tracks the current iteration that is playing. When mCurrentIteration exceeds the
117 * repeatCount (if repeatCount!=INFINITE), the animation ends
118 */
119 private int mCurrentIteration = 0;
120
121 /**
Chet Haasea00f3862011-02-22 06:34:40 -0800122 * Tracks current elapsed/eased fraction, for querying in getAnimatedFraction().
123 */
124 private float mCurrentFraction = 0f;
125
126 /**
Chet Haasea18a86b2010-09-07 13:20:00 -0700127 * Tracks whether a startDelay'd animation has begun playing through the startDelay.
128 */
129 private boolean mStartedDelay = false;
130
131 /**
132 * Tracks the time at which the animation began playing through its startDelay. This is
133 * different from the mStartTime variable, which is used to track when the animation became
134 * active (which is when the startDelay expired and the animation was added to the active
135 * animations list).
136 */
137 private long mDelayStartTime;
138
139 /**
140 * Flag that represents the current state of the animation. Used to figure out when to start
141 * an animation (if state == STOPPED). Also used to end an animation that
142 * has been cancel()'d or end()'d since the last animation frame. Possible values are
Chet Haasee2ab7cc2010-12-06 16:10:07 -0800143 * STOPPED, RUNNING, SEEKED.
Chet Haasea18a86b2010-09-07 13:20:00 -0700144 */
Chet Haase051d35e2010-12-14 07:20:58 -0800145 int mPlayingState = STOPPED;
Chet Haasea18a86b2010-09-07 13:20:00 -0700146
147 /**
Chet Haaseb8f574a2011-08-03 14:10:06 -0700148 * Additional playing state to indicate whether an animator has been start()'d. There is
149 * some lag between a call to start() and the first animation frame. We should still note
150 * that the animation has been started, even if it's first animation frame has not yet
151 * happened, and reflect that state in isRunning().
152 * Note that delayed animations are different: they are not started until their first
153 * animation frame, which occurs after their delay elapses.
154 */
Chet Haase8b699792011-08-05 15:20:19 -0700155 private boolean mRunning = false;
156
157 /**
158 * Additional playing state to indicate whether an animator has been start()'d, whether or
159 * not there is a nonzero startDelay.
160 */
Chet Haaseb8f574a2011-08-03 14:10:06 -0700161 private boolean mStarted = false;
162
163 /**
Chet Haase8aa1ffb2013-08-08 14:00:00 -0700164 * Tracks whether we've notified listeners of the onAnimationStart() event. This can be
Chet Haase17cf42c2012-04-17 13:18:14 -0700165 * complex to keep track of since we notify listeners at different times depending on
166 * startDelay and whether start() was called before end().
167 */
168 private boolean mStartListenersCalled = false;
169
170 /**
Chet Haasea18a86b2010-09-07 13:20:00 -0700171 * Flag that denotes whether the animation is set up and ready to go. Used to
172 * set up animation that has not yet been started.
173 */
174 boolean mInitialized = false;
175
176 //
177 // Backing variables
178 //
179
180 // How long the animation should last in ms
Chet Haasec38fa1f2012-02-01 16:37:46 -0800181 private long mDuration = (long)(300 * sDurationScale);
Chet Haased21a9fe2012-02-01 14:14:17 -0800182 private long mUnscaledDuration = 300;
Chet Haasea18a86b2010-09-07 13:20:00 -0700183
184 // The amount of time in ms to delay starting the animation after start() is called
185 private long mStartDelay = 0;
Chet Haased21a9fe2012-02-01 14:14:17 -0800186 private long mUnscaledStartDelay = 0;
Chet Haasea18a86b2010-09-07 13:20:00 -0700187
Chet Haasea18a86b2010-09-07 13:20:00 -0700188 // The number of times the animation will repeat. The default is 0, which means the animation
189 // will play only once
190 private int mRepeatCount = 0;
191
192 /**
193 * The type of repetition that will occur when repeatMode is nonzero. RESTART means the
194 * animation will start from the beginning on every new cycle. REVERSE means the animation
195 * will reverse directions on each iteration.
196 */
197 private int mRepeatMode = RESTART;
198
199 /**
200 * The time interpolator to be used. The elapsed fraction of the animation will be passed
201 * through this interpolator to calculate the interpolated fraction, which is then used to
202 * calculate the animated values.
203 */
Chet Haasee0ee2e92010-10-07 09:06:18 -0700204 private TimeInterpolator mInterpolator = sDefaultInterpolator;
Chet Haasea18a86b2010-09-07 13:20:00 -0700205
206 /**
207 * The set of listeners to be sent events through the life of an animation.
208 */
209 private ArrayList<AnimatorUpdateListener> mUpdateListeners = null;
210
211 /**
212 * The property/value sets being animated.
213 */
214 PropertyValuesHolder[] mValues;
215
216 /**
217 * A hashmap of the PropertyValuesHolder objects. This map is used to lookup animated values
218 * by property name during calls to getAnimatedValue(String).
219 */
220 HashMap<String, PropertyValuesHolder> mValuesMap;
221
222 /**
223 * Public constants
224 */
225
226 /**
227 * When the animation reaches the end and <code>repeatCount</code> is INFINITE
228 * or a positive value, the animation restarts from the beginning.
229 */
230 public static final int RESTART = 1;
231 /**
232 * When the animation reaches the end and <code>repeatCount</code> is INFINITE
233 * or a positive value, the animation reverses direction on every iteration.
234 */
235 public static final int REVERSE = 2;
236 /**
237 * This value used used with the {@link #setRepeatCount(int)} property to repeat
238 * the animation indefinitely.
239 */
240 public static final int INFINITE = -1;
241
Chet Haasec38fa1f2012-02-01 16:37:46 -0800242
243 /**
244 * @hide
245 */
246 public static void setDurationScale(float durationScale) {
247 sDurationScale = durationScale;
248 }
249
Chet Haasea18a86b2010-09-07 13:20:00 -0700250 /**
Jeff Brownff7e6ef2012-08-15 02:05:18 -0700251 * @hide
252 */
253 public static float getDurationScale() {
254 return sDurationScale;
255 }
256
257 /**
Chet Haasea18a86b2010-09-07 13:20:00 -0700258 * Creates a new ValueAnimator object. This default constructor is primarily for
Chet Haase2794eb32010-10-12 16:29:28 -0700259 * use internally; the factory methods which take parameters are more generally
Chet Haasea18a86b2010-09-07 13:20:00 -0700260 * useful.
261 */
262 public ValueAnimator() {
263 }
264
265 /**
Chet Haase2794eb32010-10-12 16:29:28 -0700266 * Constructs and returns a ValueAnimator that animates between int values. A single
267 * value implies that that value is the one being animated to. However, this is not typically
268 * useful in a ValueAnimator object because there is no way for the object to determine the
269 * starting value for the animation (unlike ObjectAnimator, which can derive that value
270 * from the target object and property being animated). Therefore, there should typically
271 * be two or more values.
Chet Haasea18a86b2010-09-07 13:20:00 -0700272 *
Chet Haase2794eb32010-10-12 16:29:28 -0700273 * @param values A set of values that the animation will animate between over time.
274 * @return A ValueAnimator object that is set up to animate between the given values.
Chet Haasea18a86b2010-09-07 13:20:00 -0700275 */
Chet Haase2794eb32010-10-12 16:29:28 -0700276 public static ValueAnimator ofInt(int... values) {
277 ValueAnimator anim = new ValueAnimator();
278 anim.setIntValues(values);
279 return anim;
280 }
281
282 /**
283 * Constructs and returns a ValueAnimator that animates between float values. A single
284 * value implies that that value is the one being animated to. However, this is not typically
285 * useful in a ValueAnimator object because there is no way for the object to determine the
286 * starting value for the animation (unlike ObjectAnimator, which can derive that value
287 * from the target object and property being animated). Therefore, there should typically
288 * be two or more values.
289 *
290 * @param values A set of values that the animation will animate between over time.
291 * @return A ValueAnimator object that is set up to animate between the given values.
292 */
293 public static ValueAnimator ofFloat(float... values) {
294 ValueAnimator anim = new ValueAnimator();
295 anim.setFloatValues(values);
296 return anim;
297 }
298
299 /**
Chet Haase2794eb32010-10-12 16:29:28 -0700300 * Constructs and returns a ValueAnimator that animates between the values
301 * specified in the PropertyValuesHolder objects.
302 *
303 * @param values A set of PropertyValuesHolder objects whose values will be animated
304 * between over time.
305 * @return A ValueAnimator object that is set up to animate between the given values.
306 */
307 public static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values) {
308 ValueAnimator anim = new ValueAnimator();
309 anim.setValues(values);
310 return anim;
311 }
312 /**
313 * Constructs and returns a ValueAnimator that animates between Object values. A single
314 * value implies that that value is the one being animated to. However, this is not typically
315 * useful in a ValueAnimator object because there is no way for the object to determine the
316 * starting value for the animation (unlike ObjectAnimator, which can derive that value
317 * from the target object and property being animated). Therefore, there should typically
318 * be two or more values.
319 *
320 * <p>Since ValueAnimator does not know how to animate between arbitrary Objects, this
321 * factory method also takes a TypeEvaluator object that the ValueAnimator will use
322 * to perform that interpolation.
323 *
324 * @param evaluator A TypeEvaluator that will be called on each animation frame to
325 * provide the ncessry interpolation between the Object values to derive the animated
326 * value.
327 * @param values A set of values that the animation will animate between over time.
328 * @return A ValueAnimator object that is set up to animate between the given values.
329 */
330 public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values) {
331 ValueAnimator anim = new ValueAnimator();
332 anim.setObjectValues(values);
333 anim.setEvaluator(evaluator);
334 return anim;
335 }
336
337 /**
338 * Sets int values that will be animated between. A single
339 * value implies that that value is the one being animated to. However, this is not typically
340 * useful in a ValueAnimator object because there is no way for the object to determine the
341 * starting value for the animation (unlike ObjectAnimator, which can derive that value
342 * from the target object and property being animated). Therefore, there should typically
343 * be two or more values.
344 *
345 * <p>If there are already multiple sets of values defined for this ValueAnimator via more
346 * than one PropertyValuesHolder object, this method will set the values for the first
347 * of those objects.</p>
348 *
349 * @param values A set of values that the animation will animate between over time.
350 */
351 public void setIntValues(int... values) {
352 if (values == null || values.length == 0) {
353 return;
Chet Haasea18a86b2010-09-07 13:20:00 -0700354 }
Chet Haase2794eb32010-10-12 16:29:28 -0700355 if (mValues == null || mValues.length == 0) {
Romain Guy18772ea2013-04-10 18:31:22 -0700356 setValues(PropertyValuesHolder.ofInt("", values));
Chet Haase2794eb32010-10-12 16:29:28 -0700357 } else {
358 PropertyValuesHolder valuesHolder = mValues[0];
359 valuesHolder.setIntValues(values);
360 }
361 // New property/values/target should cause re-initialization prior to starting
362 mInitialized = false;
363 }
364
365 /**
366 * Sets float values that will be animated between. A single
367 * value implies that that value is the one being animated to. However, this is not typically
368 * useful in a ValueAnimator object because there is no way for the object to determine the
369 * starting value for the animation (unlike ObjectAnimator, which can derive that value
370 * from the target object and property being animated). Therefore, there should typically
371 * be two or more values.
372 *
373 * <p>If there are already multiple sets of values defined for this ValueAnimator via more
374 * than one PropertyValuesHolder object, this method will set the values for the first
375 * of those objects.</p>
376 *
377 * @param values A set of values that the animation will animate between over time.
378 */
379 public void setFloatValues(float... values) {
380 if (values == null || values.length == 0) {
381 return;
382 }
383 if (mValues == null || mValues.length == 0) {
Romain Guy18772ea2013-04-10 18:31:22 -0700384 setValues(PropertyValuesHolder.ofFloat("", values));
Chet Haase2794eb32010-10-12 16:29:28 -0700385 } else {
386 PropertyValuesHolder valuesHolder = mValues[0];
387 valuesHolder.setFloatValues(values);
388 }
389 // New property/values/target should cause re-initialization prior to starting
390 mInitialized = false;
391 }
392
393 /**
Chet Haase2794eb32010-10-12 16:29:28 -0700394 * Sets the values to animate between for this animation. A single
395 * value implies that that value is the one being animated to. However, this is not typically
396 * useful in a ValueAnimator object because there is no way for the object to determine the
397 * starting value for the animation (unlike ObjectAnimator, which can derive that value
398 * from the target object and property being animated). Therefore, there should typically
399 * be two or more values.
400 *
401 * <p>If there are already multiple sets of values defined for this ValueAnimator via more
402 * than one PropertyValuesHolder object, this method will set the values for the first
403 * of those objects.</p>
404 *
405 * <p>There should be a TypeEvaluator set on the ValueAnimator that knows how to interpolate
406 * between these value objects. ValueAnimator only knows how to interpolate between the
407 * primitive types specified in the other setValues() methods.</p>
408 *
409 * @param values The set of values to animate between.
410 */
411 public void setObjectValues(Object... values) {
412 if (values == null || values.length == 0) {
413 return;
414 }
415 if (mValues == null || mValues.length == 0) {
Romain Guy18772ea2013-04-10 18:31:22 -0700416 setValues(PropertyValuesHolder.ofObject("", null, values));
Chet Haase2794eb32010-10-12 16:29:28 -0700417 } else {
418 PropertyValuesHolder valuesHolder = mValues[0];
419 valuesHolder.setObjectValues(values);
420 }
421 // New property/values/target should cause re-initialization prior to starting
422 mInitialized = false;
Chet Haasea18a86b2010-09-07 13:20:00 -0700423 }
424
425 /**
426 * Sets the values, per property, being animated between. This function is called internally
Ken Wakasaf76a50c2012-03-09 19:56:35 +0900427 * by the constructors of ValueAnimator that take a list of values. But a ValueAnimator can
Chet Haasea18a86b2010-09-07 13:20:00 -0700428 * be constructed without values and this method can be called to set the values manually
429 * instead.
430 *
431 * @param values The set of values, per property, being animated between.
432 */
433 public void setValues(PropertyValuesHolder... values) {
434 int numValues = values.length;
435 mValues = values;
436 mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
437 for (int i = 0; i < numValues; ++i) {
Romain Guy18772ea2013-04-10 18:31:22 -0700438 PropertyValuesHolder valuesHolder = values[i];
Chet Haasea18a86b2010-09-07 13:20:00 -0700439 mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);
440 }
Chet Haase0e0590b2010-09-26 11:57:28 -0700441 // New property/values/target should cause re-initialization prior to starting
442 mInitialized = false;
Chet Haasea18a86b2010-09-07 13:20:00 -0700443 }
444
445 /**
446 * Returns the values that this ValueAnimator animates between. These values are stored in
447 * PropertyValuesHolder objects, even if the ValueAnimator was created with a simple list
448 * of value objects instead.
449 *
450 * @return PropertyValuesHolder[] An array of PropertyValuesHolder objects which hold the
451 * values, per property, that define the animation.
452 */
453 public PropertyValuesHolder[] getValues() {
454 return mValues;
455 }
456
457 /**
Chet Haasea18a86b2010-09-07 13:20:00 -0700458 * This function is called immediately before processing the first animation
459 * frame of an animation. If there is a nonzero <code>startDelay</code>, the
460 * function is called after that delay ends.
461 * It takes care of the final initialization steps for the
462 * animation.
463 *
464 * <p>Overrides of this method should call the superclass method to ensure
465 * that internal mechanisms for the animation are set up correctly.</p>
466 */
467 void initAnimation() {
468 if (!mInitialized) {
469 int numValues = mValues.length;
470 for (int i = 0; i < numValues; ++i) {
471 mValues[i].init();
472 }
Chet Haasea18a86b2010-09-07 13:20:00 -0700473 mInitialized = true;
474 }
475 }
476
477
478 /**
Chet Haase2794eb32010-10-12 16:29:28 -0700479 * Sets the length of the animation. The default duration is 300 milliseconds.
Chet Haasea18a86b2010-09-07 13:20:00 -0700480 *
Chet Haase27c1d4d2010-12-16 07:58:28 -0800481 * @param duration The length of the animation, in milliseconds. This value cannot
482 * be negative.
Chet Haase2794eb32010-10-12 16:29:28 -0700483 * @return ValueAnimator The object called with setDuration(). This return
484 * value makes it easier to compose statements together that construct and then set the
485 * duration, as in <code>ValueAnimator.ofInt(0, 10).setDuration(500).start()</code>.
Chet Haasea18a86b2010-09-07 13:20:00 -0700486 */
Chet Haase2794eb32010-10-12 16:29:28 -0700487 public ValueAnimator setDuration(long duration) {
Chet Haase27c1d4d2010-12-16 07:58:28 -0800488 if (duration < 0) {
489 throw new IllegalArgumentException("Animators cannot have negative duration: " +
490 duration);
491 }
Chet Haased21a9fe2012-02-01 14:14:17 -0800492 mUnscaledDuration = duration;
493 mDuration = (long)(duration * sDurationScale);
Chet Haase2794eb32010-10-12 16:29:28 -0700494 return this;
Chet Haasea18a86b2010-09-07 13:20:00 -0700495 }
496
497 /**
Chet Haase2794eb32010-10-12 16:29:28 -0700498 * Gets the length of the animation. The default duration is 300 milliseconds.
Chet Haasea18a86b2010-09-07 13:20:00 -0700499 *
500 * @return The length of the animation, in milliseconds.
501 */
502 public long getDuration() {
Chet Haased21a9fe2012-02-01 14:14:17 -0800503 return mUnscaledDuration;
Chet Haasea18a86b2010-09-07 13:20:00 -0700504 }
505
506 /**
507 * Sets the position of the animation to the specified point in time. This time should
508 * be between 0 and the total duration of the animation, including any repetition. If
509 * the animation has not yet been started, then it will not advance forward after it is
510 * set to this time; it will simply set the time to this value and perform any appropriate
511 * actions based on that time. If the animation is already running, then setCurrentPlayTime()
512 * will set the current playing time to this value and continue playing from that point.
513 *
514 * @param playTime The time, in milliseconds, to which the animation is advanced or rewound.
515 */
516 public void setCurrentPlayTime(long playTime) {
517 initAnimation();
518 long currentTime = AnimationUtils.currentAnimationTimeMillis();
519 if (mPlayingState != RUNNING) {
520 mSeekTime = playTime;
521 mPlayingState = SEEKED;
522 }
523 mStartTime = currentTime - playTime;
Jeff Brown20c4f872012-04-26 17:38:21 -0700524 doAnimationFrame(currentTime);
Chet Haasea18a86b2010-09-07 13:20:00 -0700525 }
526
527 /**
528 * Gets the current position of the animation in time, which is equal to the current
529 * time minus the time that the animation started. An animation that is not yet started will
530 * return a value of zero.
531 *
532 * @return The current position in time of the animation.
533 */
534 public long getCurrentPlayTime() {
535 if (!mInitialized || mPlayingState == STOPPED) {
536 return 0;
537 }
538 return AnimationUtils.currentAnimationTimeMillis() - mStartTime;
539 }
540
541 /**
542 * This custom, static handler handles the timing pulse that is shared by
543 * all active animations. This approach ensures that the setting of animation
544 * values will happen on the UI thread and that all animations will share
545 * the same times for calculating their values, which makes synchronizing
546 * animations possible.
547 *
Jeff Brown20c4f872012-04-26 17:38:21 -0700548 * The handler uses the Choreographer for executing periodic callbacks.
Chet Haasebe19e032013-03-15 17:08:55 -0700549 *
550 * @hide
Chet Haasea18a86b2010-09-07 13:20:00 -0700551 */
Romain Guy18772ea2013-04-10 18:31:22 -0700552 @SuppressWarnings("unchecked")
Chet Haasebe19e032013-03-15 17:08:55 -0700553 protected static class AnimationHandler implements Runnable {
Jeff Brown9c38dbe2011-12-02 16:22:46 -0800554 // The per-thread list of all active animations
Chet Haasebe19e032013-03-15 17:08:55 -0700555 /** @hide */
556 protected final ArrayList<ValueAnimator> mAnimations = new ArrayList<ValueAnimator>();
Jeff Brown9c38dbe2011-12-02 16:22:46 -0800557
Chet Haase2936fc02012-08-16 14:34:04 -0700558 // Used in doAnimationFrame() to avoid concurrent modifications of mAnimations
559 private final ArrayList<ValueAnimator> mTmpAnimations = new ArrayList<ValueAnimator>();
560
Jeff Brown9c38dbe2011-12-02 16:22:46 -0800561 // The per-thread set of animations to be started on the next animation frame
Chet Haasebe19e032013-03-15 17:08:55 -0700562 /** @hide */
563 protected final ArrayList<ValueAnimator> mPendingAnimations = new ArrayList<ValueAnimator>();
Jeff Brown9c38dbe2011-12-02 16:22:46 -0800564
565 /**
566 * Internal per-thread collections used to avoid set collisions as animations start and end
567 * while being processed.
Chet Haasebe19e032013-03-15 17:08:55 -0700568 * @hide
Jeff Brown9c38dbe2011-12-02 16:22:46 -0800569 */
Chet Haasebe19e032013-03-15 17:08:55 -0700570 protected final ArrayList<ValueAnimator> mDelayedAnims = new ArrayList<ValueAnimator>();
Jeff Brown9c38dbe2011-12-02 16:22:46 -0800571 private final ArrayList<ValueAnimator> mEndingAnims = new ArrayList<ValueAnimator>();
572 private final ArrayList<ValueAnimator> mReadyAnims = new ArrayList<ValueAnimator>();
573
Jeff Brown96e942d2011-11-30 19:55:01 -0800574 private final Choreographer mChoreographer;
Jeff Brown4a06c802012-02-15 15:06:01 -0800575 private boolean mAnimationScheduled;
Jeff Brown96e942d2011-11-30 19:55:01 -0800576
577 private AnimationHandler() {
578 mChoreographer = Choreographer.getInstance();
579 }
580
Chet Haasea18a86b2010-09-07 13:20:00 -0700581 /**
Jeff Brown20c4f872012-04-26 17:38:21 -0700582 * Start animating on the next frame.
Chet Haasea18a86b2010-09-07 13:20:00 -0700583 */
Jeff Brown20c4f872012-04-26 17:38:21 -0700584 public void start() {
585 scheduleAnimation();
Chet Haasea18a86b2010-09-07 13:20:00 -0700586 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800587
Jeff Brown20c4f872012-04-26 17:38:21 -0700588 private void doAnimationFrame(long frameTime) {
Jeff Brown96e942d2011-11-30 19:55:01 -0800589 // mPendingAnimations holds any animations that have requested to be started
590 // We're going to clear mPendingAnimations, but starting animation may
591 // cause more to be added to the pending list (for example, if one animation
592 // starting triggers another starting). So we loop until mPendingAnimations
593 // is empty.
594 while (mPendingAnimations.size() > 0) {
595 ArrayList<ValueAnimator> pendingCopy =
596 (ArrayList<ValueAnimator>) mPendingAnimations.clone();
597 mPendingAnimations.clear();
598 int count = pendingCopy.size();
599 for (int i = 0; i < count; ++i) {
600 ValueAnimator anim = pendingCopy.get(i);
601 // If the animation has a startDelay, place it on the delayed list
602 if (anim.mStartDelay == 0) {
603 anim.startAnimation(this);
604 } else {
605 mDelayedAnims.add(anim);
606 }
607 }
608 }
Chet Haasec6ffab32012-03-16 16:32:26 -0700609 // Next, process animations currently sitting on the delayed queue, adding
Jeff Brown96e942d2011-11-30 19:55:01 -0800610 // them to the active animations if they are ready
611 int numDelayedAnims = mDelayedAnims.size();
612 for (int i = 0; i < numDelayedAnims; ++i) {
613 ValueAnimator anim = mDelayedAnims.get(i);
Jeff Brown20c4f872012-04-26 17:38:21 -0700614 if (anim.delayedAnimationFrame(frameTime)) {
Jeff Brown96e942d2011-11-30 19:55:01 -0800615 mReadyAnims.add(anim);
616 }
617 }
618 int numReadyAnims = mReadyAnims.size();
619 if (numReadyAnims > 0) {
620 for (int i = 0; i < numReadyAnims; ++i) {
621 ValueAnimator anim = mReadyAnims.get(i);
622 anim.startAnimation(this);
623 anim.mRunning = true;
624 mDelayedAnims.remove(anim);
625 }
626 mReadyAnims.clear();
627 }
628
629 // Now process all active animations. The return value from animationFrame()
630 // tells the handler whether it should now be ended
631 int numAnims = mAnimations.size();
Chet Haase2936fc02012-08-16 14:34:04 -0700632 for (int i = 0; i < numAnims; ++i) {
633 mTmpAnimations.add(mAnimations.get(i));
634 }
635 for (int i = 0; i < numAnims; ++i) {
636 ValueAnimator anim = mTmpAnimations.get(i);
637 if (mAnimations.contains(anim) && anim.doAnimationFrame(frameTime)) {
Jeff Brown96e942d2011-11-30 19:55:01 -0800638 mEndingAnims.add(anim);
639 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800640 }
Chet Haase2936fc02012-08-16 14:34:04 -0700641 mTmpAnimations.clear();
Jeff Brown96e942d2011-11-30 19:55:01 -0800642 if (mEndingAnims.size() > 0) {
Chet Haase2936fc02012-08-16 14:34:04 -0700643 for (int i = 0; i < mEndingAnims.size(); ++i) {
Jeff Brown96e942d2011-11-30 19:55:01 -0800644 mEndingAnims.get(i).endAnimation(this);
645 }
646 mEndingAnims.clear();
647 }
648
649 // If there are still active or delayed animations, schedule a future call to
650 // onAnimate to process the next frame of the animations.
Jeff Brown20c4f872012-04-26 17:38:21 -0700651 if (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty()) {
652 scheduleAnimation();
Jeff Brown96e942d2011-11-30 19:55:01 -0800653 }
654 }
655
Jeff Brown4a06c802012-02-15 15:06:01 -0800656 // Called by the Choreographer.
Jeff Brown96e942d2011-11-30 19:55:01 -0800657 @Override
Jeff Brown4a06c802012-02-15 15:06:01 -0800658 public void run() {
659 mAnimationScheduled = false;
Jeff Brown20c4f872012-04-26 17:38:21 -0700660 doAnimationFrame(mChoreographer.getFrameTime());
661 }
662
663 private void scheduleAnimation() {
664 if (!mAnimationScheduled) {
665 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
666 mAnimationScheduled = true;
667 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800668 }
Chet Haasea18a86b2010-09-07 13:20:00 -0700669 }
670
671 /**
672 * The amount of time, in milliseconds, to delay starting the animation after
673 * {@link #start()} is called.
674 *
675 * @return the number of milliseconds to delay running the animation
676 */
677 public long getStartDelay() {
Chet Haased21a9fe2012-02-01 14:14:17 -0800678 return mUnscaledStartDelay;
Chet Haasea18a86b2010-09-07 13:20:00 -0700679 }
680
681 /**
682 * The amount of time, in milliseconds, to delay starting the animation after
683 * {@link #start()} is called.
684
685 * @param startDelay The amount of the delay, in milliseconds
686 */
687 public void setStartDelay(long startDelay) {
Chet Haased21a9fe2012-02-01 14:14:17 -0800688 this.mStartDelay = (long)(startDelay * sDurationScale);
689 mUnscaledStartDelay = startDelay;
Chet Haasea18a86b2010-09-07 13:20:00 -0700690 }
691
692 /**
693 * The amount of time, in milliseconds, between each frame of the animation. This is a
694 * requested time that the animation will attempt to honor, but the actual delay between
695 * frames may be different, depending on system load and capabilities. This is a static
696 * function because the same delay will be applied to all animations, since they are all
697 * run off of a single timing loop.
698 *
Jeff Brown96e942d2011-11-30 19:55:01 -0800699 * The frame delay may be ignored when the animation system uses an external timing
700 * source, such as the display refresh rate (vsync), to govern animations.
701 *
Chet Haasea18a86b2010-09-07 13:20:00 -0700702 * @return the requested time between frames, in milliseconds
703 */
704 public static long getFrameDelay() {
Jeff Brown96e942d2011-11-30 19:55:01 -0800705 return Choreographer.getFrameDelay();
Chet Haasea18a86b2010-09-07 13:20:00 -0700706 }
707
708 /**
709 * The amount of time, in milliseconds, between each frame of the animation. This is a
710 * requested time that the animation will attempt to honor, but the actual delay between
711 * frames may be different, depending on system load and capabilities. This is a static
712 * function because the same delay will be applied to all animations, since they are all
713 * run off of a single timing loop.
714 *
Jeff Brown96e942d2011-11-30 19:55:01 -0800715 * The frame delay may be ignored when the animation system uses an external timing
716 * source, such as the display refresh rate (vsync), to govern animations.
717 *
Chet Haasea18a86b2010-09-07 13:20:00 -0700718 * @param frameDelay the requested time between frames, in milliseconds
719 */
720 public static void setFrameDelay(long frameDelay) {
Jeff Brown96e942d2011-11-30 19:55:01 -0800721 Choreographer.setFrameDelay(frameDelay);
Chet Haasea18a86b2010-09-07 13:20:00 -0700722 }
723
724 /**
725 * The most recent value calculated by this <code>ValueAnimator</code> when there is just one
726 * property being animated. This value is only sensible while the animation is running. The main
727 * purpose for this read-only property is to retrieve the value from the <code>ValueAnimator</code>
728 * during a call to {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)}, which
729 * is called during each animation frame, immediately after the value is calculated.
730 *
731 * @return animatedValue The value most recently calculated by this <code>ValueAnimator</code> for
732 * the single property being animated. If there are several properties being animated
733 * (specified by several PropertyValuesHolder objects in the constructor), this function
734 * returns the animated value for the first of those objects.
735 */
736 public Object getAnimatedValue() {
737 if (mValues != null && mValues.length > 0) {
738 return mValues[0].getAnimatedValue();
739 }
740 // Shouldn't get here; should always have values unless ValueAnimator was set up wrong
741 return null;
742 }
743
744 /**
745 * The most recent value calculated by this <code>ValueAnimator</code> for <code>propertyName</code>.
746 * The main purpose for this read-only property is to retrieve the value from the
747 * <code>ValueAnimator</code> during a call to
748 * {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)}, which
749 * is called during each animation frame, immediately after the value is calculated.
750 *
751 * @return animatedValue The value most recently calculated for the named property
752 * by this <code>ValueAnimator</code>.
753 */
754 public Object getAnimatedValue(String propertyName) {
755 PropertyValuesHolder valuesHolder = mValuesMap.get(propertyName);
756 if (valuesHolder != null) {
757 return valuesHolder.getAnimatedValue();
758 } else {
759 // At least avoid crashing if called with bogus propertyName
760 return null;
761 }
762 }
763
764 /**
765 * Sets how many times the animation should be repeated. If the repeat
766 * count is 0, the animation is never repeated. If the repeat count is
767 * greater than 0 or {@link #INFINITE}, the repeat mode will be taken
768 * into account. The repeat count is 0 by default.
769 *
770 * @param value the number of times the animation should be repeated
771 */
772 public void setRepeatCount(int value) {
773 mRepeatCount = value;
774 }
775 /**
776 * Defines how many times the animation should repeat. The default value
777 * is 0.
778 *
779 * @return the number of times the animation should repeat, or {@link #INFINITE}
780 */
781 public int getRepeatCount() {
782 return mRepeatCount;
783 }
784
785 /**
786 * Defines what this animation should do when it reaches the end. This
787 * setting is applied only when the repeat count is either greater than
788 * 0 or {@link #INFINITE}. Defaults to {@link #RESTART}.
789 *
790 * @param value {@link #RESTART} or {@link #REVERSE}
791 */
792 public void setRepeatMode(int value) {
793 mRepeatMode = value;
794 }
795
796 /**
797 * Defines what this animation should do when it reaches the end.
798 *
799 * @return either one of {@link #REVERSE} or {@link #RESTART}
800 */
801 public int getRepeatMode() {
802 return mRepeatMode;
803 }
804
805 /**
806 * Adds a listener to the set of listeners that are sent update events through the life of
807 * an animation. This method is called on all listeners for every frame of the animation,
808 * after the values for the animation have been calculated.
809 *
810 * @param listener the listener to be added to the current set of listeners for this animation.
811 */
812 public void addUpdateListener(AnimatorUpdateListener listener) {
813 if (mUpdateListeners == null) {
814 mUpdateListeners = new ArrayList<AnimatorUpdateListener>();
815 }
816 mUpdateListeners.add(listener);
817 }
818
819 /**
Jim Miller30604212010-09-22 19:56:23 -0700820 * Removes all listeners from the set listening to frame updates for this animation.
821 */
822 public void removeAllUpdateListeners() {
823 if (mUpdateListeners == null) {
824 return;
825 }
826 mUpdateListeners.clear();
827 mUpdateListeners = null;
828 }
829
830 /**
Chet Haasea18a86b2010-09-07 13:20:00 -0700831 * Removes a listener from the set listening to frame updates for this animation.
832 *
833 * @param listener the listener to be removed from the current set of update listeners
834 * for this animation.
835 */
836 public void removeUpdateListener(AnimatorUpdateListener listener) {
837 if (mUpdateListeners == null) {
838 return;
839 }
840 mUpdateListeners.remove(listener);
841 if (mUpdateListeners.size() == 0) {
842 mUpdateListeners = null;
843 }
844 }
845
846
847 /**
848 * The time interpolator used in calculating the elapsed fraction of this animation. The
849 * interpolator determines whether the animation runs with linear or non-linear motion,
850 * such as acceleration and deceleration. The default value is
851 * {@link android.view.animation.AccelerateDecelerateInterpolator}
852 *
Chet Haase27c1d4d2010-12-16 07:58:28 -0800853 * @param value the interpolator to be used by this animation. A value of <code>null</code>
854 * will result in linear interpolation.
Chet Haasea18a86b2010-09-07 13:20:00 -0700855 */
856 @Override
Chet Haasee0ee2e92010-10-07 09:06:18 -0700857 public void setInterpolator(TimeInterpolator value) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700858 if (value != null) {
859 mInterpolator = value;
Chet Haase27c1d4d2010-12-16 07:58:28 -0800860 } else {
861 mInterpolator = new LinearInterpolator();
Chet Haasea18a86b2010-09-07 13:20:00 -0700862 }
863 }
864
865 /**
866 * Returns the timing interpolator that this ValueAnimator uses.
867 *
868 * @return The timing interpolator for this ValueAnimator.
869 */
Chet Haase430742f2013-04-12 11:18:36 -0700870 @Override
Chet Haasee0ee2e92010-10-07 09:06:18 -0700871 public TimeInterpolator getInterpolator() {
Chet Haasea18a86b2010-09-07 13:20:00 -0700872 return mInterpolator;
873 }
874
875 /**
876 * The type evaluator to be used when calculating the animated values of this animation.
Chet Haaseb2ab04f2011-01-16 11:03:22 -0800877 * The system will automatically assign a float or int evaluator based on the type
Chet Haasea18a86b2010-09-07 13:20:00 -0700878 * of <code>startValue</code> and <code>endValue</code> in the constructor. But if these values
879 * are not one of these primitive types, or if different evaluation is desired (such as is
880 * necessary with int values that represent colors), a custom evaluator needs to be assigned.
Chet Haase53ee3312011-01-10 15:56:56 -0800881 * For example, when running an animation on color values, the {@link ArgbEvaluator}
Chet Haasea18a86b2010-09-07 13:20:00 -0700882 * should be used to get correct RGB color interpolation.
883 *
884 * <p>If this ValueAnimator has only one set of values being animated between, this evaluator
885 * will be used for that set. If there are several sets of values being animated, which is
Chet Haasefdd3ad72013-04-24 16:38:20 -0700886 * the case if PropertyValuesHolder objects were set on the ValueAnimator, then the evaluator
Chet Haasea18a86b2010-09-07 13:20:00 -0700887 * is assigned just to the first PropertyValuesHolder object.</p>
888 *
889 * @param value the evaluator to be used this animation
890 */
891 public void setEvaluator(TypeEvaluator value) {
892 if (value != null && mValues != null && mValues.length > 0) {
893 mValues[0].setEvaluator(value);
894 }
895 }
896
Chet Haase17cf42c2012-04-17 13:18:14 -0700897 private void notifyStartListeners() {
898 if (mListeners != null && !mStartListenersCalled) {
899 ArrayList<AnimatorListener> tmpListeners =
900 (ArrayList<AnimatorListener>) mListeners.clone();
901 int numListeners = tmpListeners.size();
902 for (int i = 0; i < numListeners; ++i) {
903 tmpListeners.get(i).onAnimationStart(this);
904 }
905 }
906 mStartListenersCalled = true;
907 }
908
Chet Haasea18a86b2010-09-07 13:20:00 -0700909 /**
910 * Start the animation playing. This version of start() takes a boolean flag that indicates
911 * whether the animation should play in reverse. The flag is usually false, but may be set
Chet Haase2970c492010-11-09 13:58:04 -0800912 * to true if called from the reverse() method.
913 *
914 * <p>The animation started by calling this method will be run on the thread that called
915 * this method. This thread should have a Looper on it (a runtime exception will be thrown if
916 * this is not the case). Also, if the animation will animate
917 * properties of objects in the view hierarchy, then the calling thread should be the UI
918 * thread for that view hierarchy.</p>
Chet Haasea18a86b2010-09-07 13:20:00 -0700919 *
920 * @param playBackwards Whether the ValueAnimator should start playing in reverse.
921 */
922 private void start(boolean playBackwards) {
Chet Haase2970c492010-11-09 13:58:04 -0800923 if (Looper.myLooper() == null) {
924 throw new AndroidRuntimeException("Animators may only be run on Looper threads");
Jim Miller30604212010-09-22 19:56:23 -0700925 }
Chet Haase2970c492010-11-09 13:58:04 -0800926 mPlayingBackwards = playBackwards;
Chet Haaseadd65772011-02-09 16:47:29 -0800927 mCurrentIteration = 0;
928 mPlayingState = STOPPED;
Chet Haase8b699792011-08-05 15:20:19 -0700929 mStarted = true;
Chet Haaseadd65772011-02-09 16:47:29 -0800930 mStartedDelay = false;
Chet Haase8aa1ffb2013-08-08 14:00:00 -0700931 mPaused = false;
Jeff Brown9c38dbe2011-12-02 16:22:46 -0800932 AnimationHandler animationHandler = getOrCreateAnimationHandler();
933 animationHandler.mPendingAnimations.add(this);
Chet Haase2970c492010-11-09 13:58:04 -0800934 if (mStartDelay == 0) {
Chet Haaseadd65772011-02-09 16:47:29 -0800935 // This sets the initial value of the animation, prior to actually starting it running
Jeff Brown59bbef02012-05-07 16:43:25 -0700936 setCurrentPlayTime(0);
Chet Haase154f1452011-02-23 16:53:18 -0800937 mPlayingState = STOPPED;
Chet Haase8b699792011-08-05 15:20:19 -0700938 mRunning = true;
Chet Haase17cf42c2012-04-17 13:18:14 -0700939 notifyStartListeners();
Chet Haasea18a86b2010-09-07 13:20:00 -0700940 }
Jeff Brown20c4f872012-04-26 17:38:21 -0700941 animationHandler.start();
Chet Haasea18a86b2010-09-07 13:20:00 -0700942 }
943
944 @Override
945 public void start() {
946 start(false);
947 }
948
949 @Override
950 public void cancel() {
Chet Haase2970c492010-11-09 13:58:04 -0800951 // Only cancel if the animation is actually running or has been started and is about
952 // to run
Jeff Brown9c38dbe2011-12-02 16:22:46 -0800953 AnimationHandler handler = getOrCreateAnimationHandler();
954 if (mPlayingState != STOPPED
955 || handler.mPendingAnimations.contains(this)
956 || handler.mDelayedAnims.contains(this)) {
Chet Haaseb8f574a2011-08-03 14:10:06 -0700957 // Only notify listeners if the animator has actually started
Chet Haase17cf42c2012-04-17 13:18:14 -0700958 if ((mStarted || mRunning) && mListeners != null) {
959 if (!mRunning) {
960 // If it's not yet running, then start listeners weren't called. Call them now.
961 notifyStartListeners();
962 }
Chet Haase7dfacdb2011-07-11 17:01:56 -0700963 ArrayList<AnimatorListener> tmpListeners =
964 (ArrayList<AnimatorListener>) mListeners.clone();
965 for (AnimatorListener listener : tmpListeners) {
966 listener.onAnimationCancel(this);
967 }
968 }
Jeff Brown9c38dbe2011-12-02 16:22:46 -0800969 endAnimation(handler);
Chet Haase2970c492010-11-09 13:58:04 -0800970 }
Chet Haasea18a86b2010-09-07 13:20:00 -0700971 }
972
973 @Override
974 public void end() {
Jeff Brown9c38dbe2011-12-02 16:22:46 -0800975 AnimationHandler handler = getOrCreateAnimationHandler();
976 if (!handler.mAnimations.contains(this) && !handler.mPendingAnimations.contains(this)) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700977 // Special case if the animation has not yet started; get it ready for ending
978 mStartedDelay = false;
Jeff Brown9c38dbe2011-12-02 16:22:46 -0800979 startAnimation(handler);
Chet Haase17cf42c2012-04-17 13:18:14 -0700980 mStarted = true;
Chet Haaseadd65772011-02-09 16:47:29 -0800981 } else if (!mInitialized) {
982 initAnimation();
Chet Haasea18a86b2010-09-07 13:20:00 -0700983 }
Chet Haase4dd176862012-09-12 16:33:26 -0700984 animateValue(mPlayingBackwards ? 0f : 1f);
Jeff Brown9c38dbe2011-12-02 16:22:46 -0800985 endAnimation(handler);
Chet Haasea18a86b2010-09-07 13:20:00 -0700986 }
987
988 @Override
Chet Haase8aa1ffb2013-08-08 14:00:00 -0700989 public void resume() {
990 if (mPaused) {
991 mResumed = true;
992 }
993 super.resume();
994 }
995
996 @Override
997 public void pause() {
998 boolean previouslyPaused = mPaused;
999 super.pause();
1000 if (!previouslyPaused && mPaused) {
1001 mPauseTime = -1;
1002 mResumed = false;
1003 }
1004 }
1005
1006 @Override
Chet Haasea18a86b2010-09-07 13:20:00 -07001007 public boolean isRunning() {
Chet Haase8b699792011-08-05 15:20:19 -07001008 return (mPlayingState == RUNNING || mRunning);
1009 }
1010
1011 @Override
1012 public boolean isStarted() {
1013 return mStarted;
Chet Haasea18a86b2010-09-07 13:20:00 -07001014 }
1015
1016 /**
1017 * Plays the ValueAnimator in reverse. If the animation is already running,
1018 * it will stop itself and play backwards from the point reached when reverse was called.
1019 * If the animation is not currently running, then it will start from the end and
1020 * play backwards. This behavior is only set for the current animation; future playing
1021 * of the animation will use the default behavior of playing forward.
1022 */
1023 public void reverse() {
1024 mPlayingBackwards = !mPlayingBackwards;
1025 if (mPlayingState == RUNNING) {
1026 long currentTime = AnimationUtils.currentAnimationTimeMillis();
1027 long currentPlayTime = currentTime - mStartTime;
1028 long timeLeft = mDuration - currentPlayTime;
1029 mStartTime = currentTime - timeLeft;
Chet Haasef43fb2a2013-09-06 07:59:36 -07001030 } else if (mStarted) {
1031 end();
Chet Haasea18a86b2010-09-07 13:20:00 -07001032 } else {
1033 start(true);
1034 }
1035 }
1036
1037 /**
1038 * Called internally to end an animation by removing it from the animations list. Must be
1039 * called on the UI thread.
1040 */
Jeff Brown9c38dbe2011-12-02 16:22:46 -08001041 private void endAnimation(AnimationHandler handler) {
1042 handler.mAnimations.remove(this);
1043 handler.mPendingAnimations.remove(this);
1044 handler.mDelayedAnims.remove(this);
Chet Haasea18a86b2010-09-07 13:20:00 -07001045 mPlayingState = STOPPED;
Chet Haase8aa1ffb2013-08-08 14:00:00 -07001046 mPaused = false;
Chet Haase17cf42c2012-04-17 13:18:14 -07001047 if ((mStarted || mRunning) && mListeners != null) {
1048 if (!mRunning) {
1049 // If it's not yet running, then start listeners weren't called. Call them now.
1050 notifyStartListeners();
1051 }
Chet Haasea18a86b2010-09-07 13:20:00 -07001052 ArrayList<AnimatorListener> tmpListeners =
1053 (ArrayList<AnimatorListener>) mListeners.clone();
Chet Haase7c608f22010-10-22 17:54:04 -07001054 int numListeners = tmpListeners.size();
1055 for (int i = 0; i < numListeners; ++i) {
1056 tmpListeners.get(i).onAnimationEnd(this);
Chet Haasea18a86b2010-09-07 13:20:00 -07001057 }
1058 }
Chet Haase8b699792011-08-05 15:20:19 -07001059 mRunning = false;
Chet Haaseb8f574a2011-08-03 14:10:06 -07001060 mStarted = false;
Chet Haase17cf42c2012-04-17 13:18:14 -07001061 mStartListenersCalled = false;
Chet Haasecaf46482013-03-15 13:04:42 -07001062 mPlayingBackwards = false;
Chet Haase9b80ca82013-06-04 09:37:38 -07001063 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
1064 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, getNameForTrace(),
1065 System.identityHashCode(this));
1066 }
Chet Haasea18a86b2010-09-07 13:20:00 -07001067 }
1068
1069 /**
1070 * Called internally to start an animation by adding it to the active animations list. Must be
1071 * called on the UI thread.
1072 */
Jeff Brown9c38dbe2011-12-02 16:22:46 -08001073 private void startAnimation(AnimationHandler handler) {
Chet Haase9b80ca82013-06-04 09:37:38 -07001074 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
1075 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, getNameForTrace(),
1076 System.identityHashCode(this));
1077 }
Chet Haasea18a86b2010-09-07 13:20:00 -07001078 initAnimation();
Jeff Brown9c38dbe2011-12-02 16:22:46 -08001079 handler.mAnimations.add(this);
Chet Haaseb20db3e2010-09-10 13:07:30 -07001080 if (mStartDelay > 0 && mListeners != null) {
1081 // Listeners were already notified in start() if startDelay is 0; this is
1082 // just for delayed animations
Chet Haase17cf42c2012-04-17 13:18:14 -07001083 notifyStartListeners();
Chet Haasea18a86b2010-09-07 13:20:00 -07001084 }
1085 }
1086
1087 /**
Chet Haasefdd3ad72013-04-24 16:38:20 -07001088 * Returns the name of this animator for debugging purposes.
1089 */
1090 String getNameForTrace() {
1091 return "animator";
1092 }
1093
1094
1095 /**
Chet Haasea18a86b2010-09-07 13:20:00 -07001096 * Internal function called to process an animation frame on an animation that is currently
1097 * sleeping through its <code>startDelay</code> phase. The return value indicates whether it
1098 * should be woken up and put on the active animations queue.
1099 *
1100 * @param currentTime The current animation time, used to calculate whether the animation
1101 * has exceeded its <code>startDelay</code> and should be started.
1102 * @return True if the animation's <code>startDelay</code> has been exceeded and the animation
1103 * should be added to the set of active animations.
1104 */
1105 private boolean delayedAnimationFrame(long currentTime) {
Chet Haasea18a86b2010-09-07 13:20:00 -07001106 if (!mStartedDelay) {
1107 mStartedDelay = true;
1108 mDelayStartTime = currentTime;
1109 } else {
Chet Haase8aa1ffb2013-08-08 14:00:00 -07001110 if (mPaused) {
1111 if (mPauseTime < 0) {
1112 mPauseTime = currentTime;
1113 }
1114 return false;
1115 } else if (mResumed) {
1116 mResumed = false;
1117 if (mPauseTime > 0) {
1118 // Offset by the duration that the animation was paused
1119 mDelayStartTime += (currentTime - mPauseTime);
1120 }
1121 }
Chet Haasea18a86b2010-09-07 13:20:00 -07001122 long deltaTime = currentTime - mDelayStartTime;
1123 if (deltaTime > mStartDelay) {
1124 // startDelay ended - start the anim and record the
1125 // mStartTime appropriately
1126 mStartTime = currentTime - (deltaTime - mStartDelay);
1127 mPlayingState = RUNNING;
1128 return true;
1129 }
1130 }
1131 return false;
1132 }
1133
1134 /**
1135 * This internal function processes a single animation frame for a given animation. The
1136 * currentTime parameter is the timing pulse sent by the handler, used to calculate the
1137 * elapsed duration, and therefore
1138 * the elapsed fraction, of the animation. The return value indicates whether the animation
1139 * should be ended (which happens when the elapsed time of the animation exceeds the
1140 * animation's duration, including the repeatCount).
1141 *
1142 * @param currentTime The current time, as tracked by the static timing handler
1143 * @return true if the animation's duration, including any repetitions due to
Chet Haase8aa1ffb2013-08-08 14:00:00 -07001144 * <code>repeatCount</code>, has been exceeded and the animation should be ended.
Chet Haasea18a86b2010-09-07 13:20:00 -07001145 */
Chet Haase051d35e2010-12-14 07:20:58 -08001146 boolean animationFrame(long currentTime) {
Chet Haasea18a86b2010-09-07 13:20:00 -07001147 boolean done = false;
Chet Haasea18a86b2010-09-07 13:20:00 -07001148 switch (mPlayingState) {
1149 case RUNNING:
1150 case SEEKED:
Chet Haase70d4ba12010-10-06 09:46:45 -07001151 float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f;
Chet Haasea18a86b2010-09-07 13:20:00 -07001152 if (fraction >= 1f) {
1153 if (mCurrentIteration < mRepeatCount || mRepeatCount == INFINITE) {
1154 // Time to repeat
1155 if (mListeners != null) {
Chet Haase7c608f22010-10-22 17:54:04 -07001156 int numListeners = mListeners.size();
1157 for (int i = 0; i < numListeners; ++i) {
1158 mListeners.get(i).onAnimationRepeat(this);
Chet Haasea18a86b2010-09-07 13:20:00 -07001159 }
1160 }
Chet Haasea18a86b2010-09-07 13:20:00 -07001161 if (mRepeatMode == REVERSE) {
Romain Guy18772ea2013-04-10 18:31:22 -07001162 mPlayingBackwards = !mPlayingBackwards;
Chet Haasea18a86b2010-09-07 13:20:00 -07001163 }
Chet Haase73066682010-11-29 15:55:32 -08001164 mCurrentIteration += (int)fraction;
1165 fraction = fraction % 1f;
Chet Haasea18a86b2010-09-07 13:20:00 -07001166 mStartTime += mDuration;
1167 } else {
1168 done = true;
1169 fraction = Math.min(fraction, 1.0f);
1170 }
1171 }
1172 if (mPlayingBackwards) {
1173 fraction = 1f - fraction;
1174 }
1175 animateValue(fraction);
1176 break;
Chet Haasea18a86b2010-09-07 13:20:00 -07001177 }
1178
1179 return done;
1180 }
1181
1182 /**
Jeff Brown20c4f872012-04-26 17:38:21 -07001183 * Processes a frame of the animation, adjusting the start time if needed.
1184 *
1185 * @param frameTime The frame time.
1186 * @return true if the animation has ended.
1187 */
1188 final boolean doAnimationFrame(long frameTime) {
1189 if (mPlayingState == STOPPED) {
1190 mPlayingState = RUNNING;
1191 if (mSeekTime < 0) {
1192 mStartTime = frameTime;
1193 } else {
1194 mStartTime = frameTime - mSeekTime;
1195 // Now that we're playing, reset the seek time
1196 mSeekTime = -1;
1197 }
1198 }
Chet Haase8aa1ffb2013-08-08 14:00:00 -07001199 if (mPaused) {
1200 if (mPauseTime < 0) {
1201 mPauseTime = frameTime;
1202 }
1203 return false;
1204 } else if (mResumed) {
1205 mResumed = false;
1206 if (mPauseTime > 0) {
1207 // Offset by the duration that the animation was paused
1208 mStartTime += (frameTime - mPauseTime);
1209 }
1210 }
Jeff Brown20c4f872012-04-26 17:38:21 -07001211 // The frame time might be before the start time during the first frame of
1212 // an animation. The "current time" must always be on or after the start
1213 // time to avoid animating frames at negative time intervals. In practice, this
1214 // is very rare and only happens when seeking backwards.
1215 final long currentTime = Math.max(frameTime, mStartTime);
1216 return animationFrame(currentTime);
1217 }
1218
1219 /**
Chet Haasea00f3862011-02-22 06:34:40 -08001220 * Returns the current animation fraction, which is the elapsed/interpolated fraction used in
1221 * the most recent frame update on the animation.
1222 *
1223 * @return Elapsed/interpolated fraction of the animation.
1224 */
1225 public float getAnimatedFraction() {
1226 return mCurrentFraction;
1227 }
1228
1229 /**
Chet Haasea18a86b2010-09-07 13:20:00 -07001230 * This method is called with the elapsed fraction of the animation during every
1231 * animation frame. This function turns the elapsed fraction into an interpolated fraction
1232 * and then into an animated value (from the evaluator. The function is called mostly during
1233 * animation updates, but it is also called when the <code>end()</code>
1234 * function is called, to set the final value on the property.
1235 *
1236 * <p>Overrides of this method must call the superclass to perform the calculation
1237 * of the animated value.</p>
1238 *
1239 * @param fraction The elapsed fraction of the animation.
1240 */
1241 void animateValue(float fraction) {
1242 fraction = mInterpolator.getInterpolation(fraction);
Chet Haasea00f3862011-02-22 06:34:40 -08001243 mCurrentFraction = fraction;
Chet Haasea18a86b2010-09-07 13:20:00 -07001244 int numValues = mValues.length;
1245 for (int i = 0; i < numValues; ++i) {
1246 mValues[i].calculateValue(fraction);
1247 }
1248 if (mUpdateListeners != null) {
1249 int numListeners = mUpdateListeners.size();
1250 for (int i = 0; i < numListeners; ++i) {
1251 mUpdateListeners.get(i).onAnimationUpdate(this);
1252 }
1253 }
1254 }
1255
1256 @Override
1257 public ValueAnimator clone() {
1258 final ValueAnimator anim = (ValueAnimator) super.clone();
1259 if (mUpdateListeners != null) {
1260 ArrayList<AnimatorUpdateListener> oldListeners = mUpdateListeners;
1261 anim.mUpdateListeners = new ArrayList<AnimatorUpdateListener>();
1262 int numListeners = oldListeners.size();
1263 for (int i = 0; i < numListeners; ++i) {
1264 anim.mUpdateListeners.add(oldListeners.get(i));
1265 }
1266 }
1267 anim.mSeekTime = -1;
1268 anim.mPlayingBackwards = false;
1269 anim.mCurrentIteration = 0;
1270 anim.mInitialized = false;
1271 anim.mPlayingState = STOPPED;
1272 anim.mStartedDelay = false;
1273 PropertyValuesHolder[] oldValues = mValues;
1274 if (oldValues != null) {
1275 int numValues = oldValues.length;
1276 anim.mValues = new PropertyValuesHolder[numValues];
Chet Haasea18a86b2010-09-07 13:20:00 -07001277 anim.mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
1278 for (int i = 0; i < numValues; ++i) {
Chet Haased4dd7022011-04-04 15:25:09 -07001279 PropertyValuesHolder newValuesHolder = oldValues[i].clone();
1280 anim.mValues[i] = newValuesHolder;
1281 anim.mValuesMap.put(newValuesHolder.getPropertyName(), newValuesHolder);
Chet Haasea18a86b2010-09-07 13:20:00 -07001282 }
1283 }
1284 return anim;
1285 }
1286
1287 /**
1288 * Implementors of this interface can add themselves as update listeners
1289 * to an <code>ValueAnimator</code> instance to receive callbacks on every animation
1290 * frame, after the current frame's values have been calculated for that
1291 * <code>ValueAnimator</code>.
1292 */
1293 public static interface AnimatorUpdateListener {
1294 /**
1295 * <p>Notifies the occurrence of another frame of the animation.</p>
1296 *
1297 * @param animation The animation which was repeated.
1298 */
1299 void onAnimationUpdate(ValueAnimator animation);
1300
1301 }
Brad Fitzpatrick599ca292010-10-22 14:47:03 -07001302
1303 /**
1304 * Return the number of animations currently running.
1305 *
Jeff Brown9c38dbe2011-12-02 16:22:46 -08001306 * Used by StrictMode internally to annotate violations.
1307 * May be called on arbitrary threads!
Brad Fitzpatrick599ca292010-10-22 14:47:03 -07001308 *
1309 * @hide
1310 */
1311 public static int getCurrentAnimationsCount() {
Jeff Brown9c38dbe2011-12-02 16:22:46 -08001312 AnimationHandler handler = sAnimationHandler.get();
1313 return handler != null ? handler.mAnimations.size() : 0;
Brad Fitzpatrick599ca292010-10-22 14:47:03 -07001314 }
Patrick Dubroy8901ffa2011-01-16 17:13:55 -08001315
1316 /**
1317 * Clear all animations on this thread, without canceling or ending them.
1318 * This should be used with caution.
1319 *
1320 * @hide
1321 */
1322 public static void clearAllAnimations() {
Jeff Brown9c38dbe2011-12-02 16:22:46 -08001323 AnimationHandler handler = sAnimationHandler.get();
1324 if (handler != null) {
1325 handler.mAnimations.clear();
1326 handler.mPendingAnimations.clear();
1327 handler.mDelayedAnims.clear();
1328 }
1329 }
1330
Romain Guy18772ea2013-04-10 18:31:22 -07001331 private static AnimationHandler getOrCreateAnimationHandler() {
Jeff Brown9c38dbe2011-12-02 16:22:46 -08001332 AnimationHandler handler = sAnimationHandler.get();
1333 if (handler == null) {
1334 handler = new AnimationHandler();
1335 sAnimationHandler.set(handler);
1336 }
1337 return handler;
Patrick Dubroy8901ffa2011-01-16 17:13:55 -08001338 }
Chet Haasee9140a72011-02-16 16:23:29 -08001339
1340 @Override
1341 public String toString() {
1342 String returnVal = "ValueAnimator@" + Integer.toHexString(hashCode());
1343 if (mValues != null) {
1344 for (int i = 0; i < mValues.length; ++i) {
1345 returnVal += "\n " + mValues[i].toString();
1346 }
1347 }
1348 return returnVal;
1349 }
Brad Fitzpatrick599ca292010-10-22 14:47:03 -07001350}