blob: 7880f390c1044e8277ec951f19013504815d7868 [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 /**
George Mount1ffb2802013-10-09 16:13:54 -0700283 * Constructs and returns a ValueAnimator that animates between color 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 ofArgb(int... values) {
294 ValueAnimator anim = new ValueAnimator();
295 anim.setIntValues(values);
296 anim.setEvaluator(ArgbEvaluator.getInstance());
297 return anim;
298 }
299
300 /**
Chet Haase2794eb32010-10-12 16:29:28 -0700301 * Constructs and returns a ValueAnimator that animates between float values. A single
302 * value implies that that value is the one being animated to. However, this is not typically
303 * useful in a ValueAnimator object because there is no way for the object to determine the
304 * starting value for the animation (unlike ObjectAnimator, which can derive that value
305 * from the target object and property being animated). Therefore, there should typically
306 * be two or more values.
307 *
308 * @param values A set of values that the animation will animate between over time.
309 * @return A ValueAnimator object that is set up to animate between the given values.
310 */
311 public static ValueAnimator ofFloat(float... values) {
312 ValueAnimator anim = new ValueAnimator();
313 anim.setFloatValues(values);
314 return anim;
315 }
316
317 /**
Chet Haase2794eb32010-10-12 16:29:28 -0700318 * Constructs and returns a ValueAnimator that animates between the values
319 * specified in the PropertyValuesHolder objects.
320 *
321 * @param values A set of PropertyValuesHolder objects whose values will be animated
322 * between over time.
323 * @return A ValueAnimator object that is set up to animate between the given values.
324 */
325 public static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values) {
326 ValueAnimator anim = new ValueAnimator();
327 anim.setValues(values);
328 return anim;
329 }
330 /**
331 * Constructs and returns a ValueAnimator that animates between Object values. A single
332 * value implies that that value is the one being animated to. However, this is not typically
333 * useful in a ValueAnimator object because there is no way for the object to determine the
334 * starting value for the animation (unlike ObjectAnimator, which can derive that value
335 * from the target object and property being animated). Therefore, there should typically
336 * be two or more values.
337 *
338 * <p>Since ValueAnimator does not know how to animate between arbitrary Objects, this
339 * factory method also takes a TypeEvaluator object that the ValueAnimator will use
340 * to perform that interpolation.
341 *
342 * @param evaluator A TypeEvaluator that will be called on each animation frame to
343 * provide the ncessry interpolation between the Object values to derive the animated
344 * value.
345 * @param values A set of values that the animation will animate between over time.
346 * @return A ValueAnimator object that is set up to animate between the given values.
347 */
348 public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values) {
349 ValueAnimator anim = new ValueAnimator();
350 anim.setObjectValues(values);
351 anim.setEvaluator(evaluator);
352 return anim;
353 }
354
355 /**
356 * Sets int values that will be animated between. A single
357 * value implies that that value is the one being animated to. However, this is not typically
358 * useful in a ValueAnimator object because there is no way for the object to determine the
359 * starting value for the animation (unlike ObjectAnimator, which can derive that value
360 * from the target object and property being animated). Therefore, there should typically
361 * be two or more values.
362 *
363 * <p>If there are already multiple sets of values defined for this ValueAnimator via more
364 * than one PropertyValuesHolder object, this method will set the values for the first
365 * of those objects.</p>
366 *
367 * @param values A set of values that the animation will animate between over time.
368 */
369 public void setIntValues(int... values) {
370 if (values == null || values.length == 0) {
371 return;
Chet Haasea18a86b2010-09-07 13:20:00 -0700372 }
Chet Haase2794eb32010-10-12 16:29:28 -0700373 if (mValues == null || mValues.length == 0) {
Romain Guy18772ea2013-04-10 18:31:22 -0700374 setValues(PropertyValuesHolder.ofInt("", values));
Chet Haase2794eb32010-10-12 16:29:28 -0700375 } else {
376 PropertyValuesHolder valuesHolder = mValues[0];
377 valuesHolder.setIntValues(values);
378 }
379 // New property/values/target should cause re-initialization prior to starting
380 mInitialized = false;
381 }
382
383 /**
384 * Sets float values that will be animated between. A single
385 * value implies that that value is the one being animated to. However, this is not typically
386 * useful in a ValueAnimator object because there is no way for the object to determine the
387 * starting value for the animation (unlike ObjectAnimator, which can derive that value
388 * from the target object and property being animated). Therefore, there should typically
389 * be two or more values.
390 *
391 * <p>If there are already multiple sets of values defined for this ValueAnimator via more
392 * than one PropertyValuesHolder object, this method will set the values for the first
393 * of those objects.</p>
394 *
395 * @param values A set of values that the animation will animate between over time.
396 */
397 public void setFloatValues(float... values) {
398 if (values == null || values.length == 0) {
399 return;
400 }
401 if (mValues == null || mValues.length == 0) {
Romain Guy18772ea2013-04-10 18:31:22 -0700402 setValues(PropertyValuesHolder.ofFloat("", values));
Chet Haase2794eb32010-10-12 16:29:28 -0700403 } else {
404 PropertyValuesHolder valuesHolder = mValues[0];
405 valuesHolder.setFloatValues(values);
406 }
407 // New property/values/target should cause re-initialization prior to starting
408 mInitialized = false;
409 }
410
411 /**
Chet Haase2794eb32010-10-12 16:29:28 -0700412 * Sets the values to animate between for this animation. A single
413 * value implies that that value is the one being animated to. However, this is not typically
414 * useful in a ValueAnimator object because there is no way for the object to determine the
415 * starting value for the animation (unlike ObjectAnimator, which can derive that value
416 * from the target object and property being animated). Therefore, there should typically
417 * be two or more values.
418 *
419 * <p>If there are already multiple sets of values defined for this ValueAnimator via more
420 * than one PropertyValuesHolder object, this method will set the values for the first
421 * of those objects.</p>
422 *
423 * <p>There should be a TypeEvaluator set on the ValueAnimator that knows how to interpolate
424 * between these value objects. ValueAnimator only knows how to interpolate between the
425 * primitive types specified in the other setValues() methods.</p>
426 *
427 * @param values The set of values to animate between.
428 */
429 public void setObjectValues(Object... values) {
430 if (values == null || values.length == 0) {
431 return;
432 }
433 if (mValues == null || mValues.length == 0) {
Romain Guy18772ea2013-04-10 18:31:22 -0700434 setValues(PropertyValuesHolder.ofObject("", null, values));
Chet Haase2794eb32010-10-12 16:29:28 -0700435 } else {
436 PropertyValuesHolder valuesHolder = mValues[0];
437 valuesHolder.setObjectValues(values);
438 }
439 // New property/values/target should cause re-initialization prior to starting
440 mInitialized = false;
Chet Haasea18a86b2010-09-07 13:20:00 -0700441 }
442
443 /**
444 * Sets the values, per property, being animated between. This function is called internally
Ken Wakasaf76a50c2012-03-09 19:56:35 +0900445 * by the constructors of ValueAnimator that take a list of values. But a ValueAnimator can
Chet Haasea18a86b2010-09-07 13:20:00 -0700446 * be constructed without values and this method can be called to set the values manually
447 * instead.
448 *
449 * @param values The set of values, per property, being animated between.
450 */
451 public void setValues(PropertyValuesHolder... values) {
452 int numValues = values.length;
453 mValues = values;
454 mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
455 for (int i = 0; i < numValues; ++i) {
Romain Guy18772ea2013-04-10 18:31:22 -0700456 PropertyValuesHolder valuesHolder = values[i];
Chet Haasea18a86b2010-09-07 13:20:00 -0700457 mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);
458 }
Chet Haase0e0590b2010-09-26 11:57:28 -0700459 // New property/values/target should cause re-initialization prior to starting
460 mInitialized = false;
Chet Haasea18a86b2010-09-07 13:20:00 -0700461 }
462
463 /**
464 * Returns the values that this ValueAnimator animates between. These values are stored in
465 * PropertyValuesHolder objects, even if the ValueAnimator was created with a simple list
466 * of value objects instead.
467 *
468 * @return PropertyValuesHolder[] An array of PropertyValuesHolder objects which hold the
469 * values, per property, that define the animation.
470 */
471 public PropertyValuesHolder[] getValues() {
472 return mValues;
473 }
474
475 /**
Chet Haasea18a86b2010-09-07 13:20:00 -0700476 * This function is called immediately before processing the first animation
477 * frame of an animation. If there is a nonzero <code>startDelay</code>, the
478 * function is called after that delay ends.
479 * It takes care of the final initialization steps for the
480 * animation.
481 *
482 * <p>Overrides of this method should call the superclass method to ensure
483 * that internal mechanisms for the animation are set up correctly.</p>
484 */
485 void initAnimation() {
486 if (!mInitialized) {
487 int numValues = mValues.length;
488 for (int i = 0; i < numValues; ++i) {
489 mValues[i].init();
490 }
Chet Haasea18a86b2010-09-07 13:20:00 -0700491 mInitialized = true;
492 }
493 }
494
495
496 /**
Chet Haase2794eb32010-10-12 16:29:28 -0700497 * Sets the length of the animation. The default duration is 300 milliseconds.
Chet Haasea18a86b2010-09-07 13:20:00 -0700498 *
Chet Haase27c1d4d2010-12-16 07:58:28 -0800499 * @param duration The length of the animation, in milliseconds. This value cannot
500 * be negative.
Chet Haase2794eb32010-10-12 16:29:28 -0700501 * @return ValueAnimator The object called with setDuration(). This return
502 * value makes it easier to compose statements together that construct and then set the
503 * duration, as in <code>ValueAnimator.ofInt(0, 10).setDuration(500).start()</code>.
Chet Haasea18a86b2010-09-07 13:20:00 -0700504 */
Chet Haase2794eb32010-10-12 16:29:28 -0700505 public ValueAnimator setDuration(long duration) {
Chet Haase27c1d4d2010-12-16 07:58:28 -0800506 if (duration < 0) {
507 throw new IllegalArgumentException("Animators cannot have negative duration: " +
508 duration);
509 }
Chet Haased21a9fe2012-02-01 14:14:17 -0800510 mUnscaledDuration = duration;
511 mDuration = (long)(duration * sDurationScale);
Chet Haase2794eb32010-10-12 16:29:28 -0700512 return this;
Chet Haasea18a86b2010-09-07 13:20:00 -0700513 }
514
515 /**
Chet Haase2794eb32010-10-12 16:29:28 -0700516 * Gets the length of the animation. The default duration is 300 milliseconds.
Chet Haasea18a86b2010-09-07 13:20:00 -0700517 *
518 * @return The length of the animation, in milliseconds.
519 */
520 public long getDuration() {
Chet Haased21a9fe2012-02-01 14:14:17 -0800521 return mUnscaledDuration;
Chet Haasea18a86b2010-09-07 13:20:00 -0700522 }
523
524 /**
525 * Sets the position of the animation to the specified point in time. This time should
526 * be between 0 and the total duration of the animation, including any repetition. If
527 * the animation has not yet been started, then it will not advance forward after it is
528 * set to this time; it will simply set the time to this value and perform any appropriate
529 * actions based on that time. If the animation is already running, then setCurrentPlayTime()
530 * will set the current playing time to this value and continue playing from that point.
531 *
532 * @param playTime The time, in milliseconds, to which the animation is advanced or rewound.
533 */
534 public void setCurrentPlayTime(long playTime) {
535 initAnimation();
536 long currentTime = AnimationUtils.currentAnimationTimeMillis();
537 if (mPlayingState != RUNNING) {
538 mSeekTime = playTime;
539 mPlayingState = SEEKED;
540 }
541 mStartTime = currentTime - playTime;
Jeff Brown20c4f872012-04-26 17:38:21 -0700542 doAnimationFrame(currentTime);
Chet Haasea18a86b2010-09-07 13:20:00 -0700543 }
544
545 /**
546 * Gets the current position of the animation in time, which is equal to the current
547 * time minus the time that the animation started. An animation that is not yet started will
548 * return a value of zero.
549 *
550 * @return The current position in time of the animation.
551 */
552 public long getCurrentPlayTime() {
553 if (!mInitialized || mPlayingState == STOPPED) {
554 return 0;
555 }
556 return AnimationUtils.currentAnimationTimeMillis() - mStartTime;
557 }
558
559 /**
560 * This custom, static handler handles the timing pulse that is shared by
561 * all active animations. This approach ensures that the setting of animation
562 * values will happen on the UI thread and that all animations will share
563 * the same times for calculating their values, which makes synchronizing
564 * animations possible.
565 *
Jeff Brown20c4f872012-04-26 17:38:21 -0700566 * The handler uses the Choreographer for executing periodic callbacks.
Chet Haasebe19e032013-03-15 17:08:55 -0700567 *
568 * @hide
Chet Haasea18a86b2010-09-07 13:20:00 -0700569 */
Romain Guy18772ea2013-04-10 18:31:22 -0700570 @SuppressWarnings("unchecked")
Chet Haasebe19e032013-03-15 17:08:55 -0700571 protected static class AnimationHandler implements Runnable {
Jeff Brown9c38dbe2011-12-02 16:22:46 -0800572 // The per-thread list of all active animations
Chet Haasebe19e032013-03-15 17:08:55 -0700573 /** @hide */
574 protected final ArrayList<ValueAnimator> mAnimations = new ArrayList<ValueAnimator>();
Jeff Brown9c38dbe2011-12-02 16:22:46 -0800575
Chet Haase2936fc02012-08-16 14:34:04 -0700576 // Used in doAnimationFrame() to avoid concurrent modifications of mAnimations
577 private final ArrayList<ValueAnimator> mTmpAnimations = new ArrayList<ValueAnimator>();
578
Jeff Brown9c38dbe2011-12-02 16:22:46 -0800579 // The per-thread set of animations to be started on the next animation frame
Chet Haasebe19e032013-03-15 17:08:55 -0700580 /** @hide */
581 protected final ArrayList<ValueAnimator> mPendingAnimations = new ArrayList<ValueAnimator>();
Jeff Brown9c38dbe2011-12-02 16:22:46 -0800582
583 /**
584 * Internal per-thread collections used to avoid set collisions as animations start and end
585 * while being processed.
Chet Haasebe19e032013-03-15 17:08:55 -0700586 * @hide
Jeff Brown9c38dbe2011-12-02 16:22:46 -0800587 */
Chet Haasebe19e032013-03-15 17:08:55 -0700588 protected final ArrayList<ValueAnimator> mDelayedAnims = new ArrayList<ValueAnimator>();
Jeff Brown9c38dbe2011-12-02 16:22:46 -0800589 private final ArrayList<ValueAnimator> mEndingAnims = new ArrayList<ValueAnimator>();
590 private final ArrayList<ValueAnimator> mReadyAnims = new ArrayList<ValueAnimator>();
591
Jeff Brown96e942d2011-11-30 19:55:01 -0800592 private final Choreographer mChoreographer;
Jeff Brown4a06c802012-02-15 15:06:01 -0800593 private boolean mAnimationScheduled;
Jeff Brown96e942d2011-11-30 19:55:01 -0800594
595 private AnimationHandler() {
596 mChoreographer = Choreographer.getInstance();
597 }
598
Chet Haasea18a86b2010-09-07 13:20:00 -0700599 /**
Jeff Brown20c4f872012-04-26 17:38:21 -0700600 * Start animating on the next frame.
Chet Haasea18a86b2010-09-07 13:20:00 -0700601 */
Jeff Brown20c4f872012-04-26 17:38:21 -0700602 public void start() {
603 scheduleAnimation();
Chet Haasea18a86b2010-09-07 13:20:00 -0700604 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800605
Jeff Brown20c4f872012-04-26 17:38:21 -0700606 private void doAnimationFrame(long frameTime) {
Jeff Brown96e942d2011-11-30 19:55:01 -0800607 // mPendingAnimations holds any animations that have requested to be started
608 // We're going to clear mPendingAnimations, but starting animation may
609 // cause more to be added to the pending list (for example, if one animation
610 // starting triggers another starting). So we loop until mPendingAnimations
611 // is empty.
612 while (mPendingAnimations.size() > 0) {
613 ArrayList<ValueAnimator> pendingCopy =
614 (ArrayList<ValueAnimator>) mPendingAnimations.clone();
615 mPendingAnimations.clear();
616 int count = pendingCopy.size();
617 for (int i = 0; i < count; ++i) {
618 ValueAnimator anim = pendingCopy.get(i);
619 // If the animation has a startDelay, place it on the delayed list
620 if (anim.mStartDelay == 0) {
621 anim.startAnimation(this);
622 } else {
623 mDelayedAnims.add(anim);
624 }
625 }
626 }
Chet Haasec6ffab32012-03-16 16:32:26 -0700627 // Next, process animations currently sitting on the delayed queue, adding
Jeff Brown96e942d2011-11-30 19:55:01 -0800628 // them to the active animations if they are ready
629 int numDelayedAnims = mDelayedAnims.size();
630 for (int i = 0; i < numDelayedAnims; ++i) {
631 ValueAnimator anim = mDelayedAnims.get(i);
Jeff Brown20c4f872012-04-26 17:38:21 -0700632 if (anim.delayedAnimationFrame(frameTime)) {
Jeff Brown96e942d2011-11-30 19:55:01 -0800633 mReadyAnims.add(anim);
634 }
635 }
636 int numReadyAnims = mReadyAnims.size();
637 if (numReadyAnims > 0) {
638 for (int i = 0; i < numReadyAnims; ++i) {
639 ValueAnimator anim = mReadyAnims.get(i);
640 anim.startAnimation(this);
641 anim.mRunning = true;
642 mDelayedAnims.remove(anim);
643 }
644 mReadyAnims.clear();
645 }
646
647 // Now process all active animations. The return value from animationFrame()
648 // tells the handler whether it should now be ended
649 int numAnims = mAnimations.size();
Chet Haase2936fc02012-08-16 14:34:04 -0700650 for (int i = 0; i < numAnims; ++i) {
651 mTmpAnimations.add(mAnimations.get(i));
652 }
653 for (int i = 0; i < numAnims; ++i) {
654 ValueAnimator anim = mTmpAnimations.get(i);
655 if (mAnimations.contains(anim) && anim.doAnimationFrame(frameTime)) {
Jeff Brown96e942d2011-11-30 19:55:01 -0800656 mEndingAnims.add(anim);
657 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800658 }
Chet Haase2936fc02012-08-16 14:34:04 -0700659 mTmpAnimations.clear();
Jeff Brown96e942d2011-11-30 19:55:01 -0800660 if (mEndingAnims.size() > 0) {
Chet Haase2936fc02012-08-16 14:34:04 -0700661 for (int i = 0; i < mEndingAnims.size(); ++i) {
Jeff Brown96e942d2011-11-30 19:55:01 -0800662 mEndingAnims.get(i).endAnimation(this);
663 }
664 mEndingAnims.clear();
665 }
666
667 // If there are still active or delayed animations, schedule a future call to
668 // onAnimate to process the next frame of the animations.
Jeff Brown20c4f872012-04-26 17:38:21 -0700669 if (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty()) {
670 scheduleAnimation();
Jeff Brown96e942d2011-11-30 19:55:01 -0800671 }
672 }
673
Jeff Brown4a06c802012-02-15 15:06:01 -0800674 // Called by the Choreographer.
Jeff Brown96e942d2011-11-30 19:55:01 -0800675 @Override
Jeff Brown4a06c802012-02-15 15:06:01 -0800676 public void run() {
677 mAnimationScheduled = false;
Jeff Brown20c4f872012-04-26 17:38:21 -0700678 doAnimationFrame(mChoreographer.getFrameTime());
679 }
680
681 private void scheduleAnimation() {
682 if (!mAnimationScheduled) {
683 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
684 mAnimationScheduled = true;
685 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800686 }
Chet Haasea18a86b2010-09-07 13:20:00 -0700687 }
688
689 /**
690 * The amount of time, in milliseconds, to delay starting the animation after
691 * {@link #start()} is called.
692 *
693 * @return the number of milliseconds to delay running the animation
694 */
695 public long getStartDelay() {
Chet Haased21a9fe2012-02-01 14:14:17 -0800696 return mUnscaledStartDelay;
Chet Haasea18a86b2010-09-07 13:20:00 -0700697 }
698
699 /**
700 * The amount of time, in milliseconds, to delay starting the animation after
701 * {@link #start()} is called.
702
703 * @param startDelay The amount of the delay, in milliseconds
704 */
705 public void setStartDelay(long startDelay) {
Chet Haased21a9fe2012-02-01 14:14:17 -0800706 this.mStartDelay = (long)(startDelay * sDurationScale);
707 mUnscaledStartDelay = startDelay;
Chet Haasea18a86b2010-09-07 13:20:00 -0700708 }
709
710 /**
711 * The amount of time, in milliseconds, between each frame of the animation. This is a
712 * requested time that the animation will attempt to honor, but the actual delay between
713 * frames may be different, depending on system load and capabilities. This is a static
714 * function because the same delay will be applied to all animations, since they are all
715 * run off of a single timing loop.
716 *
Jeff Brown96e942d2011-11-30 19:55:01 -0800717 * The frame delay may be ignored when the animation system uses an external timing
718 * source, such as the display refresh rate (vsync), to govern animations.
719 *
Chet Haasea18a86b2010-09-07 13:20:00 -0700720 * @return the requested time between frames, in milliseconds
721 */
722 public static long getFrameDelay() {
Jeff Brown96e942d2011-11-30 19:55:01 -0800723 return Choreographer.getFrameDelay();
Chet Haasea18a86b2010-09-07 13:20:00 -0700724 }
725
726 /**
727 * The amount of time, in milliseconds, between each frame of the animation. This is a
728 * requested time that the animation will attempt to honor, but the actual delay between
729 * frames may be different, depending on system load and capabilities. This is a static
730 * function because the same delay will be applied to all animations, since they are all
731 * run off of a single timing loop.
732 *
Jeff Brown96e942d2011-11-30 19:55:01 -0800733 * The frame delay may be ignored when the animation system uses an external timing
734 * source, such as the display refresh rate (vsync), to govern animations.
735 *
Chet Haasea18a86b2010-09-07 13:20:00 -0700736 * @param frameDelay the requested time between frames, in milliseconds
737 */
738 public static void setFrameDelay(long frameDelay) {
Jeff Brown96e942d2011-11-30 19:55:01 -0800739 Choreographer.setFrameDelay(frameDelay);
Chet Haasea18a86b2010-09-07 13:20:00 -0700740 }
741
742 /**
743 * The most recent value calculated by this <code>ValueAnimator</code> when there is just one
744 * property being animated. This value is only sensible while the animation is running. The main
745 * purpose for this read-only property is to retrieve the value from the <code>ValueAnimator</code>
746 * during a call to {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)}, which
747 * is called during each animation frame, immediately after the value is calculated.
748 *
749 * @return animatedValue The value most recently calculated by this <code>ValueAnimator</code> for
750 * the single property being animated. If there are several properties being animated
751 * (specified by several PropertyValuesHolder objects in the constructor), this function
752 * returns the animated value for the first of those objects.
753 */
754 public Object getAnimatedValue() {
755 if (mValues != null && mValues.length > 0) {
756 return mValues[0].getAnimatedValue();
757 }
758 // Shouldn't get here; should always have values unless ValueAnimator was set up wrong
759 return null;
760 }
761
762 /**
763 * The most recent value calculated by this <code>ValueAnimator</code> for <code>propertyName</code>.
764 * The main purpose for this read-only property is to retrieve the value from the
765 * <code>ValueAnimator</code> during a call to
766 * {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)}, which
767 * is called during each animation frame, immediately after the value is calculated.
768 *
769 * @return animatedValue The value most recently calculated for the named property
770 * by this <code>ValueAnimator</code>.
771 */
772 public Object getAnimatedValue(String propertyName) {
773 PropertyValuesHolder valuesHolder = mValuesMap.get(propertyName);
774 if (valuesHolder != null) {
775 return valuesHolder.getAnimatedValue();
776 } else {
777 // At least avoid crashing if called with bogus propertyName
778 return null;
779 }
780 }
781
782 /**
783 * Sets how many times the animation should be repeated. If the repeat
784 * count is 0, the animation is never repeated. If the repeat count is
785 * greater than 0 or {@link #INFINITE}, the repeat mode will be taken
786 * into account. The repeat count is 0 by default.
787 *
788 * @param value the number of times the animation should be repeated
789 */
790 public void setRepeatCount(int value) {
791 mRepeatCount = value;
792 }
793 /**
794 * Defines how many times the animation should repeat. The default value
795 * is 0.
796 *
797 * @return the number of times the animation should repeat, or {@link #INFINITE}
798 */
799 public int getRepeatCount() {
800 return mRepeatCount;
801 }
802
803 /**
804 * Defines what this animation should do when it reaches the end. This
805 * setting is applied only when the repeat count is either greater than
806 * 0 or {@link #INFINITE}. Defaults to {@link #RESTART}.
807 *
808 * @param value {@link #RESTART} or {@link #REVERSE}
809 */
810 public void setRepeatMode(int value) {
811 mRepeatMode = value;
812 }
813
814 /**
815 * Defines what this animation should do when it reaches the end.
816 *
817 * @return either one of {@link #REVERSE} or {@link #RESTART}
818 */
819 public int getRepeatMode() {
820 return mRepeatMode;
821 }
822
823 /**
824 * Adds a listener to the set of listeners that are sent update events through the life of
825 * an animation. This method is called on all listeners for every frame of the animation,
826 * after the values for the animation have been calculated.
827 *
828 * @param listener the listener to be added to the current set of listeners for this animation.
829 */
830 public void addUpdateListener(AnimatorUpdateListener listener) {
831 if (mUpdateListeners == null) {
832 mUpdateListeners = new ArrayList<AnimatorUpdateListener>();
833 }
834 mUpdateListeners.add(listener);
835 }
836
837 /**
Jim Miller30604212010-09-22 19:56:23 -0700838 * Removes all listeners from the set listening to frame updates for this animation.
839 */
840 public void removeAllUpdateListeners() {
841 if (mUpdateListeners == null) {
842 return;
843 }
844 mUpdateListeners.clear();
845 mUpdateListeners = null;
846 }
847
848 /**
Chet Haasea18a86b2010-09-07 13:20:00 -0700849 * Removes a listener from the set listening to frame updates for this animation.
850 *
851 * @param listener the listener to be removed from the current set of update listeners
852 * for this animation.
853 */
854 public void removeUpdateListener(AnimatorUpdateListener listener) {
855 if (mUpdateListeners == null) {
856 return;
857 }
858 mUpdateListeners.remove(listener);
859 if (mUpdateListeners.size() == 0) {
860 mUpdateListeners = null;
861 }
862 }
863
864
865 /**
866 * The time interpolator used in calculating the elapsed fraction of this animation. The
867 * interpolator determines whether the animation runs with linear or non-linear motion,
868 * such as acceleration and deceleration. The default value is
869 * {@link android.view.animation.AccelerateDecelerateInterpolator}
870 *
Chet Haase27c1d4d2010-12-16 07:58:28 -0800871 * @param value the interpolator to be used by this animation. A value of <code>null</code>
872 * will result in linear interpolation.
Chet Haasea18a86b2010-09-07 13:20:00 -0700873 */
874 @Override
Chet Haasee0ee2e92010-10-07 09:06:18 -0700875 public void setInterpolator(TimeInterpolator value) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700876 if (value != null) {
877 mInterpolator = value;
Chet Haase27c1d4d2010-12-16 07:58:28 -0800878 } else {
879 mInterpolator = new LinearInterpolator();
Chet Haasea18a86b2010-09-07 13:20:00 -0700880 }
881 }
882
883 /**
884 * Returns the timing interpolator that this ValueAnimator uses.
885 *
886 * @return The timing interpolator for this ValueAnimator.
887 */
Chet Haase430742f2013-04-12 11:18:36 -0700888 @Override
Chet Haasee0ee2e92010-10-07 09:06:18 -0700889 public TimeInterpolator getInterpolator() {
Chet Haasea18a86b2010-09-07 13:20:00 -0700890 return mInterpolator;
891 }
892
893 /**
894 * The type evaluator to be used when calculating the animated values of this animation.
Chet Haaseb2ab04f2011-01-16 11:03:22 -0800895 * The system will automatically assign a float or int evaluator based on the type
Chet Haasea18a86b2010-09-07 13:20:00 -0700896 * of <code>startValue</code> and <code>endValue</code> in the constructor. But if these values
897 * are not one of these primitive types, or if different evaluation is desired (such as is
898 * necessary with int values that represent colors), a custom evaluator needs to be assigned.
Chet Haase53ee3312011-01-10 15:56:56 -0800899 * For example, when running an animation on color values, the {@link ArgbEvaluator}
Chet Haasea18a86b2010-09-07 13:20:00 -0700900 * should be used to get correct RGB color interpolation.
901 *
902 * <p>If this ValueAnimator has only one set of values being animated between, this evaluator
903 * will be used for that set. If there are several sets of values being animated, which is
Chet Haasefdd3ad72013-04-24 16:38:20 -0700904 * the case if PropertyValuesHolder objects were set on the ValueAnimator, then the evaluator
Chet Haasea18a86b2010-09-07 13:20:00 -0700905 * is assigned just to the first PropertyValuesHolder object.</p>
906 *
907 * @param value the evaluator to be used this animation
908 */
909 public void setEvaluator(TypeEvaluator value) {
910 if (value != null && mValues != null && mValues.length > 0) {
911 mValues[0].setEvaluator(value);
912 }
913 }
914
Chet Haase17cf42c2012-04-17 13:18:14 -0700915 private void notifyStartListeners() {
916 if (mListeners != null && !mStartListenersCalled) {
917 ArrayList<AnimatorListener> tmpListeners =
918 (ArrayList<AnimatorListener>) mListeners.clone();
919 int numListeners = tmpListeners.size();
920 for (int i = 0; i < numListeners; ++i) {
921 tmpListeners.get(i).onAnimationStart(this);
922 }
923 }
924 mStartListenersCalled = true;
925 }
926
Chet Haasea18a86b2010-09-07 13:20:00 -0700927 /**
928 * Start the animation playing. This version of start() takes a boolean flag that indicates
929 * whether the animation should play in reverse. The flag is usually false, but may be set
Chet Haase2970c492010-11-09 13:58:04 -0800930 * to true if called from the reverse() method.
931 *
932 * <p>The animation started by calling this method will be run on the thread that called
933 * this method. This thread should have a Looper on it (a runtime exception will be thrown if
934 * this is not the case). Also, if the animation will animate
935 * properties of objects in the view hierarchy, then the calling thread should be the UI
936 * thread for that view hierarchy.</p>
Chet Haasea18a86b2010-09-07 13:20:00 -0700937 *
938 * @param playBackwards Whether the ValueAnimator should start playing in reverse.
939 */
940 private void start(boolean playBackwards) {
Chet Haase2970c492010-11-09 13:58:04 -0800941 if (Looper.myLooper() == null) {
942 throw new AndroidRuntimeException("Animators may only be run on Looper threads");
Jim Miller30604212010-09-22 19:56:23 -0700943 }
Chet Haase2970c492010-11-09 13:58:04 -0800944 mPlayingBackwards = playBackwards;
Chet Haaseadd65772011-02-09 16:47:29 -0800945 mCurrentIteration = 0;
946 mPlayingState = STOPPED;
Chet Haase8b699792011-08-05 15:20:19 -0700947 mStarted = true;
Chet Haaseadd65772011-02-09 16:47:29 -0800948 mStartedDelay = false;
Chet Haase8aa1ffb2013-08-08 14:00:00 -0700949 mPaused = false;
Jeff Brown9c38dbe2011-12-02 16:22:46 -0800950 AnimationHandler animationHandler = getOrCreateAnimationHandler();
951 animationHandler.mPendingAnimations.add(this);
Chet Haase2970c492010-11-09 13:58:04 -0800952 if (mStartDelay == 0) {
Chet Haaseadd65772011-02-09 16:47:29 -0800953 // This sets the initial value of the animation, prior to actually starting it running
Jeff Brown59bbef02012-05-07 16:43:25 -0700954 setCurrentPlayTime(0);
Chet Haase154f1452011-02-23 16:53:18 -0800955 mPlayingState = STOPPED;
Chet Haase8b699792011-08-05 15:20:19 -0700956 mRunning = true;
Chet Haase17cf42c2012-04-17 13:18:14 -0700957 notifyStartListeners();
Chet Haasea18a86b2010-09-07 13:20:00 -0700958 }
Jeff Brown20c4f872012-04-26 17:38:21 -0700959 animationHandler.start();
Chet Haasea18a86b2010-09-07 13:20:00 -0700960 }
961
962 @Override
963 public void start() {
964 start(false);
965 }
966
967 @Override
968 public void cancel() {
Chet Haase2970c492010-11-09 13:58:04 -0800969 // Only cancel if the animation is actually running or has been started and is about
970 // to run
Jeff Brown9c38dbe2011-12-02 16:22:46 -0800971 AnimationHandler handler = getOrCreateAnimationHandler();
972 if (mPlayingState != STOPPED
973 || handler.mPendingAnimations.contains(this)
974 || handler.mDelayedAnims.contains(this)) {
Chet Haaseb8f574a2011-08-03 14:10:06 -0700975 // Only notify listeners if the animator has actually started
Chet Haase17cf42c2012-04-17 13:18:14 -0700976 if ((mStarted || mRunning) && mListeners != null) {
977 if (!mRunning) {
978 // If it's not yet running, then start listeners weren't called. Call them now.
979 notifyStartListeners();
980 }
Chet Haase7dfacdb2011-07-11 17:01:56 -0700981 ArrayList<AnimatorListener> tmpListeners =
982 (ArrayList<AnimatorListener>) mListeners.clone();
983 for (AnimatorListener listener : tmpListeners) {
984 listener.onAnimationCancel(this);
985 }
986 }
Jeff Brown9c38dbe2011-12-02 16:22:46 -0800987 endAnimation(handler);
Chet Haase2970c492010-11-09 13:58:04 -0800988 }
Chet Haasea18a86b2010-09-07 13:20:00 -0700989 }
990
991 @Override
992 public void end() {
Jeff Brown9c38dbe2011-12-02 16:22:46 -0800993 AnimationHandler handler = getOrCreateAnimationHandler();
994 if (!handler.mAnimations.contains(this) && !handler.mPendingAnimations.contains(this)) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700995 // Special case if the animation has not yet started; get it ready for ending
996 mStartedDelay = false;
Jeff Brown9c38dbe2011-12-02 16:22:46 -0800997 startAnimation(handler);
Chet Haase17cf42c2012-04-17 13:18:14 -0700998 mStarted = true;
Chet Haaseadd65772011-02-09 16:47:29 -0800999 } else if (!mInitialized) {
1000 initAnimation();
Chet Haasea18a86b2010-09-07 13:20:00 -07001001 }
Chet Haase4dd176862012-09-12 16:33:26 -07001002 animateValue(mPlayingBackwards ? 0f : 1f);
Jeff Brown9c38dbe2011-12-02 16:22:46 -08001003 endAnimation(handler);
Chet Haasea18a86b2010-09-07 13:20:00 -07001004 }
1005
1006 @Override
Chet Haase8aa1ffb2013-08-08 14:00:00 -07001007 public void resume() {
1008 if (mPaused) {
1009 mResumed = true;
1010 }
1011 super.resume();
1012 }
1013
1014 @Override
1015 public void pause() {
1016 boolean previouslyPaused = mPaused;
1017 super.pause();
1018 if (!previouslyPaused && mPaused) {
1019 mPauseTime = -1;
1020 mResumed = false;
1021 }
1022 }
1023
1024 @Override
Chet Haasea18a86b2010-09-07 13:20:00 -07001025 public boolean isRunning() {
Chet Haase8b699792011-08-05 15:20:19 -07001026 return (mPlayingState == RUNNING || mRunning);
1027 }
1028
1029 @Override
1030 public boolean isStarted() {
1031 return mStarted;
Chet Haasea18a86b2010-09-07 13:20:00 -07001032 }
1033
1034 /**
1035 * Plays the ValueAnimator in reverse. If the animation is already running,
1036 * it will stop itself and play backwards from the point reached when reverse was called.
1037 * If the animation is not currently running, then it will start from the end and
1038 * play backwards. This behavior is only set for the current animation; future playing
1039 * of the animation will use the default behavior of playing forward.
1040 */
1041 public void reverse() {
1042 mPlayingBackwards = !mPlayingBackwards;
1043 if (mPlayingState == RUNNING) {
1044 long currentTime = AnimationUtils.currentAnimationTimeMillis();
1045 long currentPlayTime = currentTime - mStartTime;
1046 long timeLeft = mDuration - currentPlayTime;
1047 mStartTime = currentTime - timeLeft;
Chet Haasef43fb2a2013-09-06 07:59:36 -07001048 } else if (mStarted) {
1049 end();
Chet Haasea18a86b2010-09-07 13:20:00 -07001050 } else {
1051 start(true);
1052 }
1053 }
1054
1055 /**
1056 * Called internally to end an animation by removing it from the animations list. Must be
1057 * called on the UI thread.
1058 */
Jeff Brown9c38dbe2011-12-02 16:22:46 -08001059 private void endAnimation(AnimationHandler handler) {
1060 handler.mAnimations.remove(this);
1061 handler.mPendingAnimations.remove(this);
1062 handler.mDelayedAnims.remove(this);
Chet Haasea18a86b2010-09-07 13:20:00 -07001063 mPlayingState = STOPPED;
Chet Haase8aa1ffb2013-08-08 14:00:00 -07001064 mPaused = false;
Chet Haase17cf42c2012-04-17 13:18:14 -07001065 if ((mStarted || mRunning) && mListeners != null) {
1066 if (!mRunning) {
1067 // If it's not yet running, then start listeners weren't called. Call them now.
1068 notifyStartListeners();
1069 }
Chet Haasea18a86b2010-09-07 13:20:00 -07001070 ArrayList<AnimatorListener> tmpListeners =
1071 (ArrayList<AnimatorListener>) mListeners.clone();
Chet Haase7c608f22010-10-22 17:54:04 -07001072 int numListeners = tmpListeners.size();
1073 for (int i = 0; i < numListeners; ++i) {
1074 tmpListeners.get(i).onAnimationEnd(this);
Chet Haasea18a86b2010-09-07 13:20:00 -07001075 }
1076 }
Chet Haase8b699792011-08-05 15:20:19 -07001077 mRunning = false;
Chet Haaseb8f574a2011-08-03 14:10:06 -07001078 mStarted = false;
Chet Haase17cf42c2012-04-17 13:18:14 -07001079 mStartListenersCalled = false;
Chet Haasecaf46482013-03-15 13:04:42 -07001080 mPlayingBackwards = false;
Chet Haase9b80ca82013-06-04 09:37:38 -07001081 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
1082 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, getNameForTrace(),
1083 System.identityHashCode(this));
1084 }
Chet Haasea18a86b2010-09-07 13:20:00 -07001085 }
1086
1087 /**
1088 * Called internally to start an animation by adding it to the active animations list. Must be
1089 * called on the UI thread.
1090 */
Jeff Brown9c38dbe2011-12-02 16:22:46 -08001091 private void startAnimation(AnimationHandler handler) {
Chet Haase9b80ca82013-06-04 09:37:38 -07001092 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
1093 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, getNameForTrace(),
1094 System.identityHashCode(this));
1095 }
Chet Haasea18a86b2010-09-07 13:20:00 -07001096 initAnimation();
Jeff Brown9c38dbe2011-12-02 16:22:46 -08001097 handler.mAnimations.add(this);
Chet Haaseb20db3e2010-09-10 13:07:30 -07001098 if (mStartDelay > 0 && mListeners != null) {
1099 // Listeners were already notified in start() if startDelay is 0; this is
1100 // just for delayed animations
Chet Haase17cf42c2012-04-17 13:18:14 -07001101 notifyStartListeners();
Chet Haasea18a86b2010-09-07 13:20:00 -07001102 }
1103 }
1104
1105 /**
Chet Haasefdd3ad72013-04-24 16:38:20 -07001106 * Returns the name of this animator for debugging purposes.
1107 */
1108 String getNameForTrace() {
1109 return "animator";
1110 }
1111
1112
1113 /**
Chet Haasea18a86b2010-09-07 13:20:00 -07001114 * Internal function called to process an animation frame on an animation that is currently
1115 * sleeping through its <code>startDelay</code> phase. The return value indicates whether it
1116 * should be woken up and put on the active animations queue.
1117 *
1118 * @param currentTime The current animation time, used to calculate whether the animation
1119 * has exceeded its <code>startDelay</code> and should be started.
1120 * @return True if the animation's <code>startDelay</code> has been exceeded and the animation
1121 * should be added to the set of active animations.
1122 */
1123 private boolean delayedAnimationFrame(long currentTime) {
Chet Haasea18a86b2010-09-07 13:20:00 -07001124 if (!mStartedDelay) {
1125 mStartedDelay = true;
1126 mDelayStartTime = currentTime;
1127 } else {
Chet Haase8aa1ffb2013-08-08 14:00:00 -07001128 if (mPaused) {
1129 if (mPauseTime < 0) {
1130 mPauseTime = currentTime;
1131 }
1132 return false;
1133 } else if (mResumed) {
1134 mResumed = false;
1135 if (mPauseTime > 0) {
1136 // Offset by the duration that the animation was paused
1137 mDelayStartTime += (currentTime - mPauseTime);
1138 }
1139 }
Chet Haasea18a86b2010-09-07 13:20:00 -07001140 long deltaTime = currentTime - mDelayStartTime;
1141 if (deltaTime > mStartDelay) {
1142 // startDelay ended - start the anim and record the
1143 // mStartTime appropriately
1144 mStartTime = currentTime - (deltaTime - mStartDelay);
1145 mPlayingState = RUNNING;
1146 return true;
1147 }
1148 }
1149 return false;
1150 }
1151
1152 /**
1153 * This internal function processes a single animation frame for a given animation. The
1154 * currentTime parameter is the timing pulse sent by the handler, used to calculate the
1155 * elapsed duration, and therefore
1156 * the elapsed fraction, of the animation. The return value indicates whether the animation
1157 * should be ended (which happens when the elapsed time of the animation exceeds the
1158 * animation's duration, including the repeatCount).
1159 *
1160 * @param currentTime The current time, as tracked by the static timing handler
1161 * @return true if the animation's duration, including any repetitions due to
Chet Haase8aa1ffb2013-08-08 14:00:00 -07001162 * <code>repeatCount</code>, has been exceeded and the animation should be ended.
Chet Haasea18a86b2010-09-07 13:20:00 -07001163 */
Chet Haase051d35e2010-12-14 07:20:58 -08001164 boolean animationFrame(long currentTime) {
Chet Haasea18a86b2010-09-07 13:20:00 -07001165 boolean done = false;
Chet Haasea18a86b2010-09-07 13:20:00 -07001166 switch (mPlayingState) {
1167 case RUNNING:
1168 case SEEKED:
Chet Haase70d4ba12010-10-06 09:46:45 -07001169 float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f;
Chet Haasea18a86b2010-09-07 13:20:00 -07001170 if (fraction >= 1f) {
1171 if (mCurrentIteration < mRepeatCount || mRepeatCount == INFINITE) {
1172 // Time to repeat
1173 if (mListeners != null) {
Chet Haase7c608f22010-10-22 17:54:04 -07001174 int numListeners = mListeners.size();
1175 for (int i = 0; i < numListeners; ++i) {
1176 mListeners.get(i).onAnimationRepeat(this);
Chet Haasea18a86b2010-09-07 13:20:00 -07001177 }
1178 }
Chet Haasea18a86b2010-09-07 13:20:00 -07001179 if (mRepeatMode == REVERSE) {
Romain Guy18772ea2013-04-10 18:31:22 -07001180 mPlayingBackwards = !mPlayingBackwards;
Chet Haasea18a86b2010-09-07 13:20:00 -07001181 }
Chet Haase73066682010-11-29 15:55:32 -08001182 mCurrentIteration += (int)fraction;
1183 fraction = fraction % 1f;
Chet Haasea18a86b2010-09-07 13:20:00 -07001184 mStartTime += mDuration;
1185 } else {
1186 done = true;
1187 fraction = Math.min(fraction, 1.0f);
1188 }
1189 }
1190 if (mPlayingBackwards) {
1191 fraction = 1f - fraction;
1192 }
1193 animateValue(fraction);
1194 break;
Chet Haasea18a86b2010-09-07 13:20:00 -07001195 }
1196
1197 return done;
1198 }
1199
1200 /**
Jeff Brown20c4f872012-04-26 17:38:21 -07001201 * Processes a frame of the animation, adjusting the start time if needed.
1202 *
1203 * @param frameTime The frame time.
1204 * @return true if the animation has ended.
1205 */
1206 final boolean doAnimationFrame(long frameTime) {
1207 if (mPlayingState == STOPPED) {
1208 mPlayingState = RUNNING;
1209 if (mSeekTime < 0) {
1210 mStartTime = frameTime;
1211 } else {
1212 mStartTime = frameTime - mSeekTime;
1213 // Now that we're playing, reset the seek time
1214 mSeekTime = -1;
1215 }
1216 }
Chet Haase8aa1ffb2013-08-08 14:00:00 -07001217 if (mPaused) {
1218 if (mPauseTime < 0) {
1219 mPauseTime = frameTime;
1220 }
1221 return false;
1222 } else if (mResumed) {
1223 mResumed = false;
1224 if (mPauseTime > 0) {
1225 // Offset by the duration that the animation was paused
1226 mStartTime += (frameTime - mPauseTime);
1227 }
1228 }
Jeff Brown20c4f872012-04-26 17:38:21 -07001229 // The frame time might be before the start time during the first frame of
1230 // an animation. The "current time" must always be on or after the start
1231 // time to avoid animating frames at negative time intervals. In practice, this
1232 // is very rare and only happens when seeking backwards.
1233 final long currentTime = Math.max(frameTime, mStartTime);
1234 return animationFrame(currentTime);
1235 }
1236
1237 /**
Chet Haasea00f3862011-02-22 06:34:40 -08001238 * Returns the current animation fraction, which is the elapsed/interpolated fraction used in
1239 * the most recent frame update on the animation.
1240 *
1241 * @return Elapsed/interpolated fraction of the animation.
1242 */
1243 public float getAnimatedFraction() {
1244 return mCurrentFraction;
1245 }
1246
1247 /**
Chet Haasea18a86b2010-09-07 13:20:00 -07001248 * This method is called with the elapsed fraction of the animation during every
1249 * animation frame. This function turns the elapsed fraction into an interpolated fraction
1250 * and then into an animated value (from the evaluator. The function is called mostly during
1251 * animation updates, but it is also called when the <code>end()</code>
1252 * function is called, to set the final value on the property.
1253 *
1254 * <p>Overrides of this method must call the superclass to perform the calculation
1255 * of the animated value.</p>
1256 *
1257 * @param fraction The elapsed fraction of the animation.
1258 */
1259 void animateValue(float fraction) {
1260 fraction = mInterpolator.getInterpolation(fraction);
Chet Haasea00f3862011-02-22 06:34:40 -08001261 mCurrentFraction = fraction;
Chet Haasea18a86b2010-09-07 13:20:00 -07001262 int numValues = mValues.length;
1263 for (int i = 0; i < numValues; ++i) {
1264 mValues[i].calculateValue(fraction);
1265 }
1266 if (mUpdateListeners != null) {
1267 int numListeners = mUpdateListeners.size();
1268 for (int i = 0; i < numListeners; ++i) {
1269 mUpdateListeners.get(i).onAnimationUpdate(this);
1270 }
1271 }
1272 }
1273
1274 @Override
1275 public ValueAnimator clone() {
1276 final ValueAnimator anim = (ValueAnimator) super.clone();
1277 if (mUpdateListeners != null) {
1278 ArrayList<AnimatorUpdateListener> oldListeners = mUpdateListeners;
1279 anim.mUpdateListeners = new ArrayList<AnimatorUpdateListener>();
1280 int numListeners = oldListeners.size();
1281 for (int i = 0; i < numListeners; ++i) {
1282 anim.mUpdateListeners.add(oldListeners.get(i));
1283 }
1284 }
1285 anim.mSeekTime = -1;
1286 anim.mPlayingBackwards = false;
1287 anim.mCurrentIteration = 0;
1288 anim.mInitialized = false;
1289 anim.mPlayingState = STOPPED;
1290 anim.mStartedDelay = false;
1291 PropertyValuesHolder[] oldValues = mValues;
1292 if (oldValues != null) {
1293 int numValues = oldValues.length;
1294 anim.mValues = new PropertyValuesHolder[numValues];
Chet Haasea18a86b2010-09-07 13:20:00 -07001295 anim.mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
1296 for (int i = 0; i < numValues; ++i) {
Chet Haased4dd7022011-04-04 15:25:09 -07001297 PropertyValuesHolder newValuesHolder = oldValues[i].clone();
1298 anim.mValues[i] = newValuesHolder;
1299 anim.mValuesMap.put(newValuesHolder.getPropertyName(), newValuesHolder);
Chet Haasea18a86b2010-09-07 13:20:00 -07001300 }
1301 }
1302 return anim;
1303 }
1304
1305 /**
1306 * Implementors of this interface can add themselves as update listeners
1307 * to an <code>ValueAnimator</code> instance to receive callbacks on every animation
1308 * frame, after the current frame's values have been calculated for that
1309 * <code>ValueAnimator</code>.
1310 */
1311 public static interface AnimatorUpdateListener {
1312 /**
1313 * <p>Notifies the occurrence of another frame of the animation.</p>
1314 *
1315 * @param animation The animation which was repeated.
1316 */
1317 void onAnimationUpdate(ValueAnimator animation);
1318
1319 }
Brad Fitzpatrick599ca292010-10-22 14:47:03 -07001320
1321 /**
1322 * Return the number of animations currently running.
1323 *
Jeff Brown9c38dbe2011-12-02 16:22:46 -08001324 * Used by StrictMode internally to annotate violations.
1325 * May be called on arbitrary threads!
Brad Fitzpatrick599ca292010-10-22 14:47:03 -07001326 *
1327 * @hide
1328 */
1329 public static int getCurrentAnimationsCount() {
Jeff Brown9c38dbe2011-12-02 16:22:46 -08001330 AnimationHandler handler = sAnimationHandler.get();
1331 return handler != null ? handler.mAnimations.size() : 0;
Brad Fitzpatrick599ca292010-10-22 14:47:03 -07001332 }
Patrick Dubroy8901ffa2011-01-16 17:13:55 -08001333
1334 /**
1335 * Clear all animations on this thread, without canceling or ending them.
1336 * This should be used with caution.
1337 *
1338 * @hide
1339 */
1340 public static void clearAllAnimations() {
Jeff Brown9c38dbe2011-12-02 16:22:46 -08001341 AnimationHandler handler = sAnimationHandler.get();
1342 if (handler != null) {
1343 handler.mAnimations.clear();
1344 handler.mPendingAnimations.clear();
1345 handler.mDelayedAnims.clear();
1346 }
1347 }
1348
Romain Guy18772ea2013-04-10 18:31:22 -07001349 private static AnimationHandler getOrCreateAnimationHandler() {
Jeff Brown9c38dbe2011-12-02 16:22:46 -08001350 AnimationHandler handler = sAnimationHandler.get();
1351 if (handler == null) {
1352 handler = new AnimationHandler();
1353 sAnimationHandler.set(handler);
1354 }
1355 return handler;
Patrick Dubroy8901ffa2011-01-16 17:13:55 -08001356 }
Chet Haasee9140a72011-02-16 16:23:29 -08001357
1358 @Override
1359 public String toString() {
1360 String returnVal = "ValueAnimator@" + Integer.toHexString(hashCode());
1361 if (mValues != null) {
1362 for (int i = 0; i < mValues.length; ++i) {
1363 returnVal += "\n " + mValues[i].toString();
1364 }
1365 }
1366 return returnVal;
1367 }
Brad Fitzpatrick599ca292010-10-22 14:47:03 -07001368}