blob: 0a9b5ded892477a38af4bf659ad115ce221dafeb [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
Tor Norbyec615c6f2015-03-02 10:11:44 -080019import android.annotation.CallSuper;
George Mount7764b922016-01-13 14:51:33 -080020import android.annotation.IntDef;
Chet Haasea18a86b2010-09-07 13:20:00 -070021import android.os.Looper;
Romain Guy18772ea2013-04-10 18:31:22 -070022import android.os.Trace;
Chet Haase2970c492010-11-09 13:58:04 -080023import android.util.AndroidRuntimeException;
Jeff Brownc42b28d2015-04-06 19:49:02 -070024import android.util.Log;
Chet Haasea18a86b2010-09-07 13:20:00 -070025import android.view.animation.AccelerateDecelerateInterpolator;
26import android.view.animation.AnimationUtils;
Chet Haase27c1d4d2010-12-16 07:58:28 -080027import android.view.animation.LinearInterpolator;
Chet Haasea18a86b2010-09-07 13:20:00 -070028
George Mount7764b922016-01-13 14:51:33 -080029import java.lang.annotation.Retention;
30import java.lang.annotation.RetentionPolicy;
Chet Haasea18a86b2010-09-07 13:20:00 -070031import java.util.ArrayList;
32import java.util.HashMap;
33
34/**
35 * This class provides a simple timing engine for running animations
36 * which calculate animated values and set them on target objects.
37 *
38 * <p>There is a single timing pulse that all animations use. It runs in a
39 * custom handler to ensure that property changes happen on the UI thread.</p>
40 *
41 * <p>By default, ValueAnimator uses non-linear time interpolation, via the
42 * {@link AccelerateDecelerateInterpolator} class, which accelerates into and decelerates
43 * out of an animation. This behavior can be changed by calling
Chet Haasee0ee2e92010-10-07 09:06:18 -070044 * {@link ValueAnimator#setInterpolator(TimeInterpolator)}.</p>
Joe Fernandez3aef8e1d2011-12-20 10:38:34 -080045 *
Chet Haased4307532014-12-01 06:32:38 -080046 * <p>Animators can be created from either code or resource files. Here is an example
47 * of a ValueAnimator resource file:</p>
48 *
49 * {@sample development/samples/ApiDemos/res/anim/animator.xml ValueAnimatorResources}
50 *
51 * <p>It is also possible to use a combination of {@link PropertyValuesHolder} and
52 * {@link Keyframe} resource tags to create a multi-step animation.
53 * Note that you can specify explicit fractional values (from 0 to 1) for
54 * each keyframe to determine when, in the overall duration, the animation should arrive at that
55 * value. Alternatively, you can leave the fractions off and the keyframes will be equally
56 * distributed within the total duration:</p>
57 *
58 * {@sample development/samples/ApiDemos/res/anim/value_animator_pvh_kf.xml
59 * ValueAnimatorKeyframeResources}
60 *
Joe Fernandez3aef8e1d2011-12-20 10:38:34 -080061 * <div class="special reference">
62 * <h3>Developer Guides</h3>
63 * <p>For more information about animating with {@code ValueAnimator}, read the
64 * <a href="{@docRoot}guide/topics/graphics/prop-animation.html#value-animator">Property
65 * Animation</a> developer guide.</p>
66 * </div>
Chet Haasea18a86b2010-09-07 13:20:00 -070067 */
Romain Guy18772ea2013-04-10 18:31:22 -070068@SuppressWarnings("unchecked")
Doris Liu3618d302015-08-14 11:11:08 -070069public class ValueAnimator extends Animator implements AnimationHandler.AnimationFrameCallback {
Jeff Brownc42b28d2015-04-06 19:49:02 -070070 private static final String TAG = "ValueAnimator";
71 private static final boolean DEBUG = false;
Chet Haasea18a86b2010-09-07 13:20:00 -070072
73 /**
74 * Internal constants
75 */
Chet Haased21a9fe2012-02-01 14:14:17 -080076 private static float sDurationScale = 1.0f;
Chet Haasea18a86b2010-09-07 13:20:00 -070077
Chet Haasea18a86b2010-09-07 13:20:00 -070078 /**
Chet Haasea18a86b2010-09-07 13:20:00 -070079 * Internal variables
80 * NOTE: This object implements the clone() method, making a deep copy of any referenced
81 * objects. As other non-trivial fields are added to this class, make sure to add logic
82 * to clone() to make deep copies of them.
83 */
84
Jeff Brownc42b28d2015-04-06 19:49:02 -070085 /**
86 * The first time that the animation's animateFrame() method is called. This time is used to
87 * determine elapsed time (and therefore the elapsed fraction) in subsequent calls
88 * to animateFrame().
89 *
90 * Whenever mStartTime is set, you must also update mStartTimeCommitted.
91 */
Chet Haase051d35e2010-12-14 07:20:58 -080092 long mStartTime;
Chet Haasea18a86b2010-09-07 13:20:00 -070093
94 /**
Jeff Brownc42b28d2015-04-06 19:49:02 -070095 * When true, the start time has been firmly committed as a chosen reference point in
96 * time by which the progress of the animation will be evaluated. When false, the
97 * start time may be updated when the first animation frame is committed so as
98 * to compensate for jank that may have occurred between when the start time was
99 * initialized and when the frame was actually drawn.
100 *
101 * This flag is generally set to false during the first frame of the animation
102 * when the animation playing state transitions from STOPPED to RUNNING or
103 * resumes after having been paused. This flag is set to true when the start time
104 * is firmly committed and should not be further compensated for jank.
105 */
106 boolean mStartTimeCommitted;
107
108 /**
Chet Haasea18a86b2010-09-07 13:20:00 -0700109 * Set when setCurrentPlayTime() is called. If negative, animation is not currently seeked
110 * to a value.
111 */
Chet Haase0d1c27a2014-11-03 18:35:16 +0000112 float mSeekFraction = -1;
Chet Haasea18a86b2010-09-07 13:20:00 -0700113
Chet Haase8aa1ffb2013-08-08 14:00:00 -0700114 /**
115 * Set on the next frame after pause() is called, used to calculate a new startTime
116 * or delayStartTime which allows the animator to continue from the point at which
117 * it was paused. If negative, has not yet been set.
118 */
119 private long mPauseTime;
120
121 /**
122 * Set when an animator is resumed. This triggers logic in the next frame which
123 * actually resumes the animator.
124 */
125 private boolean mResumed = false;
126
Chet Haasea18a86b2010-09-07 13:20:00 -0700127 // The time interpolator to be used if none is set on the animation
Chet Haasee0ee2e92010-10-07 09:06:18 -0700128 private static final TimeInterpolator sDefaultInterpolator =
129 new AccelerateDecelerateInterpolator();
Chet Haasea18a86b2010-09-07 13:20:00 -0700130
Chet Haasea18a86b2010-09-07 13:20:00 -0700131 /**
Chet Haasef4e3bab2014-12-02 17:51:34 -0800132 * Flag to indicate whether this animator is playing in reverse mode, specifically
133 * by being started or interrupted by a call to reverse(). This flag is different than
134 * mPlayingBackwards, which indicates merely whether the current iteration of the
135 * animator is playing in reverse. It is used in corner cases to determine proper end
136 * behavior.
137 */
138 private boolean mReversing;
139
140 /**
Doris Liufbe94ec2015-09-09 14:52:59 -0700141 * Tracks the overall fraction of the animation, ranging from 0 to mRepeatCount + 1
Chet Haasea18a86b2010-09-07 13:20:00 -0700142 */
Doris Liufbe94ec2015-09-09 14:52:59 -0700143 private float mOverallFraction = 0f;
Chet Haasea18a86b2010-09-07 13:20:00 -0700144
145 /**
Chet Haasea00f3862011-02-22 06:34:40 -0800146 * Tracks current elapsed/eased fraction, for querying in getAnimatedFraction().
Doris Liufbe94ec2015-09-09 14:52:59 -0700147 * This is calculated by interpolating the fraction (range: [0, 1]) in the current iteration.
Chet Haasea00f3862011-02-22 06:34:40 -0800148 */
149 private float mCurrentFraction = 0f;
150
151 /**
Doris Liu3618d302015-08-14 11:11:08 -0700152 * Tracks the time (in milliseconds) when the last frame arrived.
Chet Haasea18a86b2010-09-07 13:20:00 -0700153 */
Doris Liu3618d302015-08-14 11:11:08 -0700154 private long mLastFrameTime = 0;
Chet Haasea18a86b2010-09-07 13:20:00 -0700155
156 /**
Chet Haaseb8f574a2011-08-03 14:10:06 -0700157 * Additional playing state to indicate whether an animator has been start()'d. There is
158 * some lag between a call to start() and the first animation frame. We should still note
159 * that the animation has been started, even if it's first animation frame has not yet
160 * happened, and reflect that state in isRunning().
161 * Note that delayed animations are different: they are not started until their first
162 * animation frame, which occurs after their delay elapses.
163 */
Chet Haase8b699792011-08-05 15:20:19 -0700164 private boolean mRunning = false;
165
166 /**
167 * Additional playing state to indicate whether an animator has been start()'d, whether or
168 * not there is a nonzero startDelay.
169 */
Chet Haaseb8f574a2011-08-03 14:10:06 -0700170 private boolean mStarted = false;
171
172 /**
Chet Haase8aa1ffb2013-08-08 14:00:00 -0700173 * Tracks whether we've notified listeners of the onAnimationStart() event. This can be
Chet Haase17cf42c2012-04-17 13:18:14 -0700174 * complex to keep track of since we notify listeners at different times depending on
175 * startDelay and whether start() was called before end().
176 */
177 private boolean mStartListenersCalled = false;
178
179 /**
Chet Haasea18a86b2010-09-07 13:20:00 -0700180 * Flag that denotes whether the animation is set up and ready to go. Used to
181 * set up animation that has not yet been started.
182 */
183 boolean mInitialized = false;
184
Doris Liu3dbaae12015-08-27 14:56:30 -0700185 /**
186 * Flag that tracks whether animation has been requested to end.
187 */
188 private boolean mAnimationEndRequested = false;
189
Chet Haasea18a86b2010-09-07 13:20:00 -0700190 //
191 // Backing variables
192 //
193
194 // How long the animation should last in ms
Doris Liufbe94ec2015-09-09 14:52:59 -0700195 private long mDuration = 300;
Chet Haasea18a86b2010-09-07 13:20:00 -0700196
Doris Liufbe94ec2015-09-09 14:52:59 -0700197 // The amount of time in ms to delay starting the animation after start() is called. Note
198 // that this start delay is unscaled. When there is a duration scale set on the animator, the
199 // scaling factor will be applied to this delay.
200 private long mStartDelay = 0;
Chet Haasea18a86b2010-09-07 13:20:00 -0700201
Chet Haasea18a86b2010-09-07 13:20:00 -0700202 // The number of times the animation will repeat. The default is 0, which means the animation
203 // will play only once
204 private int mRepeatCount = 0;
205
206 /**
207 * The type of repetition that will occur when repeatMode is nonzero. RESTART means the
208 * animation will start from the beginning on every new cycle. REVERSE means the animation
209 * will reverse directions on each iteration.
210 */
211 private int mRepeatMode = RESTART;
212
213 /**
214 * The time interpolator to be used. The elapsed fraction of the animation will be passed
215 * through this interpolator to calculate the interpolated fraction, which is then used to
216 * calculate the animated values.
217 */
Chet Haasee0ee2e92010-10-07 09:06:18 -0700218 private TimeInterpolator mInterpolator = sDefaultInterpolator;
Chet Haasea18a86b2010-09-07 13:20:00 -0700219
220 /**
221 * The set of listeners to be sent events through the life of an animation.
222 */
John Reckd3de42c2014-07-15 14:29:33 -0700223 ArrayList<AnimatorUpdateListener> mUpdateListeners = null;
Chet Haasea18a86b2010-09-07 13:20:00 -0700224
225 /**
226 * The property/value sets being animated.
227 */
228 PropertyValuesHolder[] mValues;
229
230 /**
231 * A hashmap of the PropertyValuesHolder objects. This map is used to lookup animated values
232 * by property name during calls to getAnimatedValue(String).
233 */
234 HashMap<String, PropertyValuesHolder> mValuesMap;
235
236 /**
237 * Public constants
238 */
239
George Mount7764b922016-01-13 14:51:33 -0800240 /** @hide */
241 @IntDef({RESTART, REVERSE})
242 @Retention(RetentionPolicy.SOURCE)
243 public @interface RepeatMode {}
244
Chet Haasea18a86b2010-09-07 13:20:00 -0700245 /**
246 * When the animation reaches the end and <code>repeatCount</code> is INFINITE
247 * or a positive value, the animation restarts from the beginning.
248 */
249 public static final int RESTART = 1;
250 /**
251 * When the animation reaches the end and <code>repeatCount</code> is INFINITE
252 * or a positive value, the animation reverses direction on every iteration.
253 */
254 public static final int REVERSE = 2;
255 /**
256 * This value used used with the {@link #setRepeatCount(int)} property to repeat
257 * the animation indefinitely.
258 */
259 public static final int INFINITE = -1;
260
Chet Haasec38fa1f2012-02-01 16:37:46 -0800261 /**
262 * @hide
263 */
264 public static void setDurationScale(float durationScale) {
265 sDurationScale = durationScale;
266 }
267
Chet Haasea18a86b2010-09-07 13:20:00 -0700268 /**
Jeff Brownff7e6ef2012-08-15 02:05:18 -0700269 * @hide
270 */
271 public static float getDurationScale() {
272 return sDurationScale;
273 }
274
275 /**
Chet Haasea18a86b2010-09-07 13:20:00 -0700276 * Creates a new ValueAnimator object. This default constructor is primarily for
Chet Haase2794eb32010-10-12 16:29:28 -0700277 * use internally; the factory methods which take parameters are more generally
Chet Haasea18a86b2010-09-07 13:20:00 -0700278 * useful.
279 */
280 public ValueAnimator() {
281 }
282
283 /**
Chet Haase2794eb32010-10-12 16:29:28 -0700284 * Constructs and returns a ValueAnimator that animates between int values. A single
285 * value implies that that value is the one being animated to. However, this is not typically
286 * useful in a ValueAnimator object because there is no way for the object to determine the
287 * starting value for the animation (unlike ObjectAnimator, which can derive that value
288 * from the target object and property being animated). Therefore, there should typically
289 * be two or more values.
Chet Haasea18a86b2010-09-07 13:20:00 -0700290 *
Chet Haase2794eb32010-10-12 16:29:28 -0700291 * @param values A set of values that the animation will animate between over time.
292 * @return A ValueAnimator object that is set up to animate between the given values.
Chet Haasea18a86b2010-09-07 13:20:00 -0700293 */
Chet Haase2794eb32010-10-12 16:29:28 -0700294 public static ValueAnimator ofInt(int... values) {
295 ValueAnimator anim = new ValueAnimator();
296 anim.setIntValues(values);
297 return anim;
298 }
299
300 /**
George Mount1ffb2802013-10-09 16:13:54 -0700301 * Constructs and returns a ValueAnimator that animates between color 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 ofArgb(int... values) {
312 ValueAnimator anim = new ValueAnimator();
313 anim.setIntValues(values);
314 anim.setEvaluator(ArgbEvaluator.getInstance());
315 return anim;
316 }
317
318 /**
Chet Haase2794eb32010-10-12 16:29:28 -0700319 * Constructs and returns a ValueAnimator that animates between float values. A single
320 * value implies that that value is the one being animated to. However, this is not typically
321 * useful in a ValueAnimator object because there is no way for the object to determine the
322 * starting value for the animation (unlike ObjectAnimator, which can derive that value
323 * from the target object and property being animated). Therefore, there should typically
324 * be two or more values.
325 *
326 * @param values A set of values that the animation will animate between over time.
327 * @return A ValueAnimator object that is set up to animate between the given values.
328 */
329 public static ValueAnimator ofFloat(float... values) {
330 ValueAnimator anim = new ValueAnimator();
331 anim.setFloatValues(values);
332 return anim;
333 }
334
335 /**
Chet Haase2794eb32010-10-12 16:29:28 -0700336 * Constructs and returns a ValueAnimator that animates between the values
337 * specified in the PropertyValuesHolder objects.
338 *
339 * @param values A set of PropertyValuesHolder objects whose values will be animated
340 * between over time.
341 * @return A ValueAnimator object that is set up to animate between the given values.
342 */
343 public static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values) {
344 ValueAnimator anim = new ValueAnimator();
345 anim.setValues(values);
346 return anim;
347 }
348 /**
349 * Constructs and returns a ValueAnimator that animates between Object values. A single
350 * value implies that that value is the one being animated to. However, this is not typically
351 * useful in a ValueAnimator object because there is no way for the object to determine the
352 * starting value for the animation (unlike ObjectAnimator, which can derive that value
353 * from the target object and property being animated). Therefore, there should typically
354 * be two or more values.
355 *
Chet Haasefa21bdf2016-04-21 17:41:54 -0700356 * <p><strong>Note:</strong> The Object values are stored as references to the original
357 * objects, which means that changes to those objects after this method is called will
358 * affect the values on the animator. If the objects will be mutated externally after
359 * this method is called, callers should pass a copy of those objects instead.
360 *
Chet Haase2794eb32010-10-12 16:29:28 -0700361 * <p>Since ValueAnimator does not know how to animate between arbitrary Objects, this
362 * factory method also takes a TypeEvaluator object that the ValueAnimator will use
363 * to perform that interpolation.
364 *
365 * @param evaluator A TypeEvaluator that will be called on each animation frame to
366 * provide the ncessry interpolation between the Object values to derive the animated
367 * value.
368 * @param values A set of values that the animation will animate between over time.
369 * @return A ValueAnimator object that is set up to animate between the given values.
370 */
371 public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values) {
372 ValueAnimator anim = new ValueAnimator();
373 anim.setObjectValues(values);
374 anim.setEvaluator(evaluator);
375 return anim;
376 }
377
378 /**
379 * Sets int values that will be animated between. A single
380 * value implies that that value is the one being animated to. However, this is not typically
381 * useful in a ValueAnimator object because there is no way for the object to determine the
382 * starting value for the animation (unlike ObjectAnimator, which can derive that value
383 * from the target object and property being animated). Therefore, there should typically
384 * be two or more values.
385 *
386 * <p>If there are already multiple sets of values defined for this ValueAnimator via more
387 * than one PropertyValuesHolder object, this method will set the values for the first
388 * of those objects.</p>
389 *
390 * @param values A set of values that the animation will animate between over time.
391 */
392 public void setIntValues(int... values) {
393 if (values == null || values.length == 0) {
394 return;
Chet Haasea18a86b2010-09-07 13:20:00 -0700395 }
Chet Haase2794eb32010-10-12 16:29:28 -0700396 if (mValues == null || mValues.length == 0) {
Romain Guy18772ea2013-04-10 18:31:22 -0700397 setValues(PropertyValuesHolder.ofInt("", values));
Chet Haase2794eb32010-10-12 16:29:28 -0700398 } else {
399 PropertyValuesHolder valuesHolder = mValues[0];
400 valuesHolder.setIntValues(values);
401 }
402 // New property/values/target should cause re-initialization prior to starting
403 mInitialized = false;
404 }
405
406 /**
407 * Sets float values that will be animated between. A single
408 * value implies that that value is the one being animated to. However, this is not typically
409 * useful in a ValueAnimator object because there is no way for the object to determine the
410 * starting value for the animation (unlike ObjectAnimator, which can derive that value
411 * from the target object and property being animated). Therefore, there should typically
412 * be two or more values.
413 *
414 * <p>If there are already multiple sets of values defined for this ValueAnimator via more
415 * than one PropertyValuesHolder object, this method will set the values for the first
416 * of those objects.</p>
417 *
418 * @param values A set of values that the animation will animate between over time.
419 */
420 public void setFloatValues(float... values) {
421 if (values == null || values.length == 0) {
422 return;
423 }
424 if (mValues == null || mValues.length == 0) {
Romain Guy18772ea2013-04-10 18:31:22 -0700425 setValues(PropertyValuesHolder.ofFloat("", values));
Chet Haase2794eb32010-10-12 16:29:28 -0700426 } else {
427 PropertyValuesHolder valuesHolder = mValues[0];
428 valuesHolder.setFloatValues(values);
429 }
430 // New property/values/target should cause re-initialization prior to starting
431 mInitialized = false;
432 }
433
434 /**
Chet Haase2794eb32010-10-12 16:29:28 -0700435 * Sets the values to animate between for this animation. A single
436 * value implies that that value is the one being animated to. However, this is not typically
437 * useful in a ValueAnimator object because there is no way for the object to determine the
438 * starting value for the animation (unlike ObjectAnimator, which can derive that value
439 * from the target object and property being animated). Therefore, there should typically
440 * be two or more values.
441 *
Chet Haasefa21bdf2016-04-21 17:41:54 -0700442 * <p><strong>Note:</strong> The Object values are stored as references to the original
443 * objects, which means that changes to those objects after this method is called will
444 * affect the values on the animator. If the objects will be mutated externally after
445 * this method is called, callers should pass a copy of those objects instead.
446 *
Chet Haase2794eb32010-10-12 16:29:28 -0700447 * <p>If there are already multiple sets of values defined for this ValueAnimator via more
448 * than one PropertyValuesHolder object, this method will set the values for the first
449 * of those objects.</p>
450 *
451 * <p>There should be a TypeEvaluator set on the ValueAnimator that knows how to interpolate
452 * between these value objects. ValueAnimator only knows how to interpolate between the
453 * primitive types specified in the other setValues() methods.</p>
454 *
455 * @param values The set of values to animate between.
456 */
457 public void setObjectValues(Object... values) {
458 if (values == null || values.length == 0) {
459 return;
460 }
461 if (mValues == null || mValues.length == 0) {
Romain Guy18772ea2013-04-10 18:31:22 -0700462 setValues(PropertyValuesHolder.ofObject("", null, values));
Chet Haase2794eb32010-10-12 16:29:28 -0700463 } else {
464 PropertyValuesHolder valuesHolder = mValues[0];
465 valuesHolder.setObjectValues(values);
466 }
467 // New property/values/target should cause re-initialization prior to starting
468 mInitialized = false;
Chet Haasea18a86b2010-09-07 13:20:00 -0700469 }
470
471 /**
472 * Sets the values, per property, being animated between. This function is called internally
Ken Wakasaf76a50c2012-03-09 19:56:35 +0900473 * by the constructors of ValueAnimator that take a list of values. But a ValueAnimator can
Chet Haasea18a86b2010-09-07 13:20:00 -0700474 * be constructed without values and this method can be called to set the values manually
475 * instead.
476 *
477 * @param values The set of values, per property, being animated between.
478 */
479 public void setValues(PropertyValuesHolder... values) {
480 int numValues = values.length;
481 mValues = values;
482 mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
483 for (int i = 0; i < numValues; ++i) {
Romain Guy18772ea2013-04-10 18:31:22 -0700484 PropertyValuesHolder valuesHolder = values[i];
Chet Haasea18a86b2010-09-07 13:20:00 -0700485 mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);
486 }
Chet Haase0e0590b2010-09-26 11:57:28 -0700487 // New property/values/target should cause re-initialization prior to starting
488 mInitialized = false;
Chet Haasea18a86b2010-09-07 13:20:00 -0700489 }
490
491 /**
492 * Returns the values that this ValueAnimator animates between. These values are stored in
493 * PropertyValuesHolder objects, even if the ValueAnimator was created with a simple list
494 * of value objects instead.
495 *
496 * @return PropertyValuesHolder[] An array of PropertyValuesHolder objects which hold the
497 * values, per property, that define the animation.
498 */
499 public PropertyValuesHolder[] getValues() {
500 return mValues;
501 }
502
503 /**
Chet Haasea18a86b2010-09-07 13:20:00 -0700504 * This function is called immediately before processing the first animation
505 * frame of an animation. If there is a nonzero <code>startDelay</code>, the
506 * function is called after that delay ends.
507 * It takes care of the final initialization steps for the
508 * animation.
509 *
510 * <p>Overrides of this method should call the superclass method to ensure
511 * that internal mechanisms for the animation are set up correctly.</p>
512 */
Tor Norbyec615c6f2015-03-02 10:11:44 -0800513 @CallSuper
Chet Haasea18a86b2010-09-07 13:20:00 -0700514 void initAnimation() {
515 if (!mInitialized) {
516 int numValues = mValues.length;
517 for (int i = 0; i < numValues; ++i) {
518 mValues[i].init();
519 }
Chet Haasea18a86b2010-09-07 13:20:00 -0700520 mInitialized = true;
521 }
522 }
523
Chet Haasea18a86b2010-09-07 13:20:00 -0700524 /**
Chet Haase2794eb32010-10-12 16:29:28 -0700525 * Sets the length of the animation. The default duration is 300 milliseconds.
Chet Haasea18a86b2010-09-07 13:20:00 -0700526 *
Chet Haase27c1d4d2010-12-16 07:58:28 -0800527 * @param duration The length of the animation, in milliseconds. This value cannot
528 * be negative.
Chet Haase2794eb32010-10-12 16:29:28 -0700529 * @return ValueAnimator The object called with setDuration(). This return
530 * value makes it easier to compose statements together that construct and then set the
531 * duration, as in <code>ValueAnimator.ofInt(0, 10).setDuration(500).start()</code>.
Chet Haasea18a86b2010-09-07 13:20:00 -0700532 */
Jeff Brownc42b28d2015-04-06 19:49:02 -0700533 @Override
Chet Haase2794eb32010-10-12 16:29:28 -0700534 public ValueAnimator setDuration(long duration) {
Chet Haase27c1d4d2010-12-16 07:58:28 -0800535 if (duration < 0) {
536 throw new IllegalArgumentException("Animators cannot have negative duration: " +
537 duration);
538 }
Doris Liufbe94ec2015-09-09 14:52:59 -0700539 mDuration = duration;
Chet Haase2794eb32010-10-12 16:29:28 -0700540 return this;
Chet Haasea18a86b2010-09-07 13:20:00 -0700541 }
542
Doris Liufbe94ec2015-09-09 14:52:59 -0700543 private long getScaledDuration() {
544 return (long)(mDuration * sDurationScale);
Jeff Brown7a08fe02014-10-07 15:55:35 -0700545 }
546
Chet Haasea18a86b2010-09-07 13:20:00 -0700547 /**
Chet Haase2794eb32010-10-12 16:29:28 -0700548 * Gets the length of the animation. The default duration is 300 milliseconds.
Chet Haasea18a86b2010-09-07 13:20:00 -0700549 *
550 * @return The length of the animation, in milliseconds.
551 */
Jeff Brownc42b28d2015-04-06 19:49:02 -0700552 @Override
Chet Haasea18a86b2010-09-07 13:20:00 -0700553 public long getDuration() {
Doris Liufbe94ec2015-09-09 14:52:59 -0700554 return mDuration;
Chet Haasea18a86b2010-09-07 13:20:00 -0700555 }
556
Doris Liu13099142015-07-10 17:32:41 -0700557 @Override
558 public long getTotalDuration() {
559 if (mRepeatCount == INFINITE) {
560 return DURATION_INFINITE;
561 } else {
Doris Liufbe94ec2015-09-09 14:52:59 -0700562 return mStartDelay + (mDuration * (mRepeatCount + 1));
Doris Liu13099142015-07-10 17:32:41 -0700563 }
564 }
565
566 /**
Chet Haasea18a86b2010-09-07 13:20:00 -0700567 * Sets the position of the animation to the specified point in time. This time should
568 * be between 0 and the total duration of the animation, including any repetition. If
569 * the animation has not yet been started, then it will not advance forward after it is
570 * set to this time; it will simply set the time to this value and perform any appropriate
571 * actions based on that time. If the animation is already running, then setCurrentPlayTime()
572 * will set the current playing time to this value and continue playing from that point.
573 *
574 * @param playTime The time, in milliseconds, to which the animation is advanced or rewound.
575 */
576 public void setCurrentPlayTime(long playTime) {
Doris Liufbe94ec2015-09-09 14:52:59 -0700577 float fraction = mDuration > 0 ? (float) playTime / mDuration : 1;
Chet Haase0d1c27a2014-11-03 18:35:16 +0000578 setCurrentFraction(fraction);
579 }
580
581 /**
582 * Sets the position of the animation to the specified fraction. This fraction should
583 * be between 0 and the total fraction of the animation, including any repetition. That is,
584 * a fraction of 0 will position the animation at the beginning, a value of 1 at the end,
Chet Haasef4e3bab2014-12-02 17:51:34 -0800585 * and a value of 2 at the end of a reversing animator that repeats once. If
Chet Haase0d1c27a2014-11-03 18:35:16 +0000586 * the animation has not yet been started, then it will not advance forward after it is
587 * set to this fraction; it will simply set the fraction to this value and perform any
588 * appropriate actions based on that fraction. If the animation is already running, then
589 * setCurrentFraction() will set the current fraction to this value and continue
Eino-Ville Talvala5a5afe02014-12-05 11:11:45 -0800590 * playing from that point. {@link Animator.AnimatorListener} events are not called
Chet Haasef4e3bab2014-12-02 17:51:34 -0800591 * due to changing the fraction; those events are only processed while the animation
592 * is running.
Chet Haase0d1c27a2014-11-03 18:35:16 +0000593 *
Chet Haasef4e3bab2014-12-02 17:51:34 -0800594 * @param fraction The fraction to which the animation is advanced or rewound. Values
595 * outside the range of 0 to the maximum fraction for the animator will be clamped to
596 * the correct range.
Chet Haase0d1c27a2014-11-03 18:35:16 +0000597 */
598 public void setCurrentFraction(float fraction) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700599 initAnimation();
Doris Liufbe94ec2015-09-09 14:52:59 -0700600 fraction = clampFraction(fraction);
601 long seekTime = (long) (getScaledDuration() * fraction);
Chet Haasef4e3bab2014-12-02 17:51:34 -0800602 long currentTime = AnimationUtils.currentAnimationTimeMillis();
603 mStartTime = currentTime - seekTime;
Jeff Brownc42b28d2015-04-06 19:49:02 -0700604 mStartTimeCommitted = true; // do not allow start time to be compensated for jank
Doris Liu3618d302015-08-14 11:11:08 -0700605 if (!mRunning) {
Chet Haase0d1c27a2014-11-03 18:35:16 +0000606 mSeekFraction = fraction;
Chet Haasea18a86b2010-09-07 13:20:00 -0700607 }
Doris Liufbe94ec2015-09-09 14:52:59 -0700608 mOverallFraction = fraction;
609 final float currentIterationFraction = getCurrentIterationFraction(fraction);
610 animateValue(currentIterationFraction);
611 }
612
613 /**
614 * Calculates current iteration based on the overall fraction. The overall fraction will be
615 * in the range of [0, mRepeatCount + 1]. Both current iteration and fraction in the current
616 * iteration can be derived from it.
617 */
618 private int getCurrentIteration(float fraction) {
619 fraction = clampFraction(fraction);
620 // If the overall fraction is a positive integer, we consider the current iteration to be
621 // complete. In other words, the fraction for the current iteration would be 1, and the
622 // current iteration would be overall fraction - 1.
623 double iteration = Math.floor(fraction);
624 if (fraction == iteration && fraction > 0) {
625 iteration--;
Chet Haasef4e3bab2014-12-02 17:51:34 -0800626 }
Doris Liufbe94ec2015-09-09 14:52:59 -0700627 return (int) iteration;
628 }
629
630 /**
631 * Calculates the fraction of the current iteration, taking into account whether the animation
632 * should be played backwards. E.g. When the animation is played backwards in an iteration,
633 * the fraction for that iteration will go from 1f to 0f.
634 */
635 private float getCurrentIterationFraction(float fraction) {
636 fraction = clampFraction(fraction);
637 int iteration = getCurrentIteration(fraction);
638 float currentFraction = fraction - iteration;
639 return shouldPlayBackward(iteration) ? 1f - currentFraction : currentFraction;
640 }
641
642 /**
643 * Clamps fraction into the correct range: [0, mRepeatCount + 1]. If repeat count is infinite,
644 * no upper bound will be set for the fraction.
645 *
646 * @param fraction fraction to be clamped
647 * @return fraction clamped into the range of [0, mRepeatCount + 1]
648 */
649 private float clampFraction(float fraction) {
650 if (fraction < 0) {
651 fraction = 0;
652 } else if (mRepeatCount != INFINITE) {
653 fraction = Math.min(fraction, mRepeatCount + 1);
654 }
655 return fraction;
656 }
657
658 /**
659 * Calculates the direction of animation playing (i.e. forward or backward), based on 1)
660 * whether the entire animation is being reversed, 2) repeat mode applied to the current
661 * iteration.
662 */
663 private boolean shouldPlayBackward(int iteration) {
664 if (iteration > 0 && mRepeatMode == REVERSE &&
665 (iteration < (mRepeatCount + 1) || mRepeatCount == INFINITE)) {
666 // if we were seeked to some other iteration in a reversing animator,
667 // figure out the correct direction to start playing based on the iteration
668 if (mReversing) {
669 return (iteration % 2) == 0;
670 } else {
671 return (iteration % 2) != 0;
672 }
673 } else {
674 return mReversing;
675 }
Chet Haasea18a86b2010-09-07 13:20:00 -0700676 }
677
678 /**
679 * Gets the current position of the animation in time, which is equal to the current
680 * time minus the time that the animation started. An animation that is not yet started will
Chet Haase4365e5a2015-10-06 19:32:57 -0700681 * return a value of zero, unless the animation has has its play time set via
682 * {@link #setCurrentPlayTime(long)} or {@link #setCurrentFraction(float)}, in which case
683 * it will return the time that was set.
Chet Haasea18a86b2010-09-07 13:20:00 -0700684 *
685 * @return The current position in time of the animation.
686 */
687 public long getCurrentPlayTime() {
Chet Haase4365e5a2015-10-06 19:32:57 -0700688 if (!mInitialized || (!mStarted && mSeekFraction < 0)) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700689 return 0;
690 }
Chet Haase4365e5a2015-10-06 19:32:57 -0700691 if (mSeekFraction >= 0) {
Doris Liufbe94ec2015-09-09 14:52:59 -0700692 return (long) (mDuration * mSeekFraction);
Chet Haase4365e5a2015-10-06 19:32:57 -0700693 }
Doris Liufbe94ec2015-09-09 14:52:59 -0700694 float durationScale = sDurationScale == 0 ? 1 : sDurationScale;
695 return (long) ((AnimationUtils.currentAnimationTimeMillis() - mStartTime) / durationScale);
Chet Haasea18a86b2010-09-07 13:20:00 -0700696 }
697
698 /**
Chet Haasea18a86b2010-09-07 13:20:00 -0700699 * The amount of time, in milliseconds, to delay starting the animation after
700 * {@link #start()} is called.
701 *
702 * @return the number of milliseconds to delay running the animation
703 */
Jeff Brownc42b28d2015-04-06 19:49:02 -0700704 @Override
Chet Haasea18a86b2010-09-07 13:20:00 -0700705 public long getStartDelay() {
Doris Liufbe94ec2015-09-09 14:52:59 -0700706 return mStartDelay;
Chet Haasea18a86b2010-09-07 13:20:00 -0700707 }
708
709 /**
710 * The amount of time, in milliseconds, to delay starting the animation after
711 * {@link #start()} is called.
712
713 * @param startDelay The amount of the delay, in milliseconds
714 */
Jeff Brownc42b28d2015-04-06 19:49:02 -0700715 @Override
Chet Haasea18a86b2010-09-07 13:20:00 -0700716 public void setStartDelay(long startDelay) {
Doris Liufbe94ec2015-09-09 14:52:59 -0700717 mStartDelay = startDelay;
Chet Haasea18a86b2010-09-07 13:20:00 -0700718 }
719
720 /**
721 * The amount of time, in milliseconds, between each frame of the animation. This is a
722 * requested time that the animation will attempt to honor, but the actual delay between
723 * frames may be different, depending on system load and capabilities. This is a static
724 * function because the same delay will be applied to all animations, since they are all
725 * run off of a single timing loop.
726 *
Jeff Brown96e942d2011-11-30 19:55:01 -0800727 * The frame delay may be ignored when the animation system uses an external timing
728 * source, such as the display refresh rate (vsync), to govern animations.
729 *
Doris Liu2b2e2c82015-10-01 11:08:54 -0700730 * Note that this method should be called from the same thread that {@link #start()} is
731 * called in order to check the frame delay for that animation. A runtime exception will be
732 * thrown if the calling thread does not have a Looper.
733 *
Chet Haasea18a86b2010-09-07 13:20:00 -0700734 * @return the requested time between frames, in milliseconds
735 */
736 public static long getFrameDelay() {
Doris Liu3618d302015-08-14 11:11:08 -0700737 return AnimationHandler.getInstance().getFrameDelay();
Chet Haasea18a86b2010-09-07 13:20:00 -0700738 }
739
740 /**
741 * The amount of time, in milliseconds, between each frame of the animation. This is a
742 * requested time that the animation will attempt to honor, but the actual delay between
743 * frames may be different, depending on system load and capabilities. This is a static
744 * function because the same delay will be applied to all animations, since they are all
745 * run off of a single timing loop.
746 *
Jeff Brown96e942d2011-11-30 19:55:01 -0800747 * The frame delay may be ignored when the animation system uses an external timing
748 * source, such as the display refresh rate (vsync), to govern animations.
749 *
Doris Liu2b2e2c82015-10-01 11:08:54 -0700750 * Note that this method should be called from the same thread that {@link #start()} is
751 * called in order to have the new frame delay take effect on that animation. A runtime
752 * exception will be thrown if the calling thread does not have a Looper.
753 *
Chet Haasea18a86b2010-09-07 13:20:00 -0700754 * @param frameDelay the requested time between frames, in milliseconds
755 */
756 public static void setFrameDelay(long frameDelay) {
Doris Liu3618d302015-08-14 11:11:08 -0700757 AnimationHandler.getInstance().setFrameDelay(frameDelay);
Chet Haasea18a86b2010-09-07 13:20:00 -0700758 }
759
760 /**
761 * The most recent value calculated by this <code>ValueAnimator</code> when there is just one
762 * property being animated. This value is only sensible while the animation is running. The main
763 * purpose for this read-only property is to retrieve the value from the <code>ValueAnimator</code>
764 * during a call to {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)}, which
765 * is called during each animation frame, immediately after the value is calculated.
766 *
767 * @return animatedValue The value most recently calculated by this <code>ValueAnimator</code> for
768 * the single property being animated. If there are several properties being animated
769 * (specified by several PropertyValuesHolder objects in the constructor), this function
770 * returns the animated value for the first of those objects.
771 */
772 public Object getAnimatedValue() {
773 if (mValues != null && mValues.length > 0) {
774 return mValues[0].getAnimatedValue();
775 }
776 // Shouldn't get here; should always have values unless ValueAnimator was set up wrong
777 return null;
778 }
779
780 /**
781 * The most recent value calculated by this <code>ValueAnimator</code> for <code>propertyName</code>.
782 * The main purpose for this read-only property is to retrieve the value from the
783 * <code>ValueAnimator</code> during a call to
784 * {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)}, which
785 * is called during each animation frame, immediately after the value is calculated.
786 *
787 * @return animatedValue The value most recently calculated for the named property
788 * by this <code>ValueAnimator</code>.
789 */
790 public Object getAnimatedValue(String propertyName) {
791 PropertyValuesHolder valuesHolder = mValuesMap.get(propertyName);
792 if (valuesHolder != null) {
793 return valuesHolder.getAnimatedValue();
794 } else {
795 // At least avoid crashing if called with bogus propertyName
796 return null;
797 }
798 }
799
800 /**
801 * Sets how many times the animation should be repeated. If the repeat
802 * count is 0, the animation is never repeated. If the repeat count is
803 * greater than 0 or {@link #INFINITE}, the repeat mode will be taken
804 * into account. The repeat count is 0 by default.
805 *
806 * @param value the number of times the animation should be repeated
807 */
808 public void setRepeatCount(int value) {
809 mRepeatCount = value;
810 }
811 /**
812 * Defines how many times the animation should repeat. The default value
813 * is 0.
814 *
815 * @return the number of times the animation should repeat, or {@link #INFINITE}
816 */
817 public int getRepeatCount() {
818 return mRepeatCount;
819 }
820
821 /**
822 * Defines what this animation should do when it reaches the end. This
823 * setting is applied only when the repeat count is either greater than
824 * 0 or {@link #INFINITE}. Defaults to {@link #RESTART}.
825 *
826 * @param value {@link #RESTART} or {@link #REVERSE}
827 */
George Mount7764b922016-01-13 14:51:33 -0800828 public void setRepeatMode(@RepeatMode int value) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700829 mRepeatMode = value;
830 }
831
832 /**
833 * Defines what this animation should do when it reaches the end.
834 *
835 * @return either one of {@link #REVERSE} or {@link #RESTART}
836 */
George Mount7764b922016-01-13 14:51:33 -0800837 @RepeatMode
Chet Haasea18a86b2010-09-07 13:20:00 -0700838 public int getRepeatMode() {
839 return mRepeatMode;
840 }
841
842 /**
843 * Adds a listener to the set of listeners that are sent update events through the life of
844 * an animation. This method is called on all listeners for every frame of the animation,
845 * after the values for the animation have been calculated.
846 *
847 * @param listener the listener to be added to the current set of listeners for this animation.
848 */
849 public void addUpdateListener(AnimatorUpdateListener listener) {
850 if (mUpdateListeners == null) {
851 mUpdateListeners = new ArrayList<AnimatorUpdateListener>();
852 }
853 mUpdateListeners.add(listener);
854 }
855
856 /**
Jim Miller30604212010-09-22 19:56:23 -0700857 * Removes all listeners from the set listening to frame updates for this animation.
858 */
859 public void removeAllUpdateListeners() {
860 if (mUpdateListeners == null) {
861 return;
862 }
863 mUpdateListeners.clear();
864 mUpdateListeners = null;
865 }
866
867 /**
Chet Haasea18a86b2010-09-07 13:20:00 -0700868 * Removes a listener from the set listening to frame updates for this animation.
869 *
870 * @param listener the listener to be removed from the current set of update listeners
871 * for this animation.
872 */
873 public void removeUpdateListener(AnimatorUpdateListener listener) {
874 if (mUpdateListeners == null) {
875 return;
876 }
877 mUpdateListeners.remove(listener);
878 if (mUpdateListeners.size() == 0) {
879 mUpdateListeners = null;
880 }
881 }
882
883
884 /**
885 * The time interpolator used in calculating the elapsed fraction of this animation. The
886 * interpolator determines whether the animation runs with linear or non-linear motion,
887 * such as acceleration and deceleration. The default value is
888 * {@link android.view.animation.AccelerateDecelerateInterpolator}
889 *
Chet Haase27c1d4d2010-12-16 07:58:28 -0800890 * @param value the interpolator to be used by this animation. A value of <code>null</code>
891 * will result in linear interpolation.
Chet Haasea18a86b2010-09-07 13:20:00 -0700892 */
893 @Override
Chet Haasee0ee2e92010-10-07 09:06:18 -0700894 public void setInterpolator(TimeInterpolator value) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700895 if (value != null) {
896 mInterpolator = value;
Chet Haase27c1d4d2010-12-16 07:58:28 -0800897 } else {
898 mInterpolator = new LinearInterpolator();
Chet Haasea18a86b2010-09-07 13:20:00 -0700899 }
900 }
901
902 /**
903 * Returns the timing interpolator that this ValueAnimator uses.
904 *
905 * @return The timing interpolator for this ValueAnimator.
906 */
Chet Haase430742f2013-04-12 11:18:36 -0700907 @Override
Chet Haasee0ee2e92010-10-07 09:06:18 -0700908 public TimeInterpolator getInterpolator() {
Chet Haasea18a86b2010-09-07 13:20:00 -0700909 return mInterpolator;
910 }
911
912 /**
913 * The type evaluator to be used when calculating the animated values of this animation.
Chet Haaseb2ab04f2011-01-16 11:03:22 -0800914 * The system will automatically assign a float or int evaluator based on the type
Chet Haasea18a86b2010-09-07 13:20:00 -0700915 * of <code>startValue</code> and <code>endValue</code> in the constructor. But if these values
916 * are not one of these primitive types, or if different evaluation is desired (such as is
917 * necessary with int values that represent colors), a custom evaluator needs to be assigned.
Chet Haase53ee3312011-01-10 15:56:56 -0800918 * For example, when running an animation on color values, the {@link ArgbEvaluator}
Chet Haasea18a86b2010-09-07 13:20:00 -0700919 * should be used to get correct RGB color interpolation.
920 *
921 * <p>If this ValueAnimator has only one set of values being animated between, this evaluator
922 * will be used for that set. If there are several sets of values being animated, which is
Chet Haasefdd3ad72013-04-24 16:38:20 -0700923 * the case if PropertyValuesHolder objects were set on the ValueAnimator, then the evaluator
Chet Haasea18a86b2010-09-07 13:20:00 -0700924 * is assigned just to the first PropertyValuesHolder object.</p>
925 *
926 * @param value the evaluator to be used this animation
927 */
928 public void setEvaluator(TypeEvaluator value) {
929 if (value != null && mValues != null && mValues.length > 0) {
930 mValues[0].setEvaluator(value);
931 }
932 }
933
Chet Haase17cf42c2012-04-17 13:18:14 -0700934 private void notifyStartListeners() {
935 if (mListeners != null && !mStartListenersCalled) {
936 ArrayList<AnimatorListener> tmpListeners =
937 (ArrayList<AnimatorListener>) mListeners.clone();
938 int numListeners = tmpListeners.size();
939 for (int i = 0; i < numListeners; ++i) {
940 tmpListeners.get(i).onAnimationStart(this);
941 }
942 }
943 mStartListenersCalled = true;
944 }
945
Chet Haasea18a86b2010-09-07 13:20:00 -0700946 /**
947 * Start the animation playing. This version of start() takes a boolean flag that indicates
948 * whether the animation should play in reverse. The flag is usually false, but may be set
Chet Haase2970c492010-11-09 13:58:04 -0800949 * to true if called from the reverse() method.
950 *
951 * <p>The animation started by calling this method will be run on the thread that called
952 * this method. This thread should have a Looper on it (a runtime exception will be thrown if
953 * this is not the case). Also, if the animation will animate
954 * properties of objects in the view hierarchy, then the calling thread should be the UI
955 * thread for that view hierarchy.</p>
Chet Haasea18a86b2010-09-07 13:20:00 -0700956 *
957 * @param playBackwards Whether the ValueAnimator should start playing in reverse.
958 */
959 private void start(boolean playBackwards) {
Chet Haase2970c492010-11-09 13:58:04 -0800960 if (Looper.myLooper() == null) {
961 throw new AndroidRuntimeException("Animators may only be run on Looper threads");
Jim Miller30604212010-09-22 19:56:23 -0700962 }
Chet Haasef4e3bab2014-12-02 17:51:34 -0800963 mReversing = playBackwards;
Doris Liufbe94ec2015-09-09 14:52:59 -0700964 // Special case: reversing from seek-to-0 should act as if not seeked at all.
965 if (playBackwards && mSeekFraction != -1 && mSeekFraction != 0) {
966 if (mRepeatCount == INFINITE) {
967 // Calculate the fraction of the current iteration.
968 float fraction = (float) (mSeekFraction - Math.floor(mSeekFraction));
969 mSeekFraction = 1 - fraction;
Chet Haasef4e3bab2014-12-02 17:51:34 -0800970 } else {
Doris Liufbe94ec2015-09-09 14:52:59 -0700971 mSeekFraction = 1 + mRepeatCount - mSeekFraction;
Chet Haasef4e3bab2014-12-02 17:51:34 -0800972 }
973 }
Chet Haase8b699792011-08-05 15:20:19 -0700974 mStarted = true;
Chet Haase8aa1ffb2013-08-08 14:00:00 -0700975 mPaused = false;
Doris Liu3618d302015-08-14 11:11:08 -0700976 mRunning = false;
Doris Liu3618d302015-08-14 11:11:08 -0700977 AnimationHandler animationHandler = AnimationHandler.getInstance();
Doris Liufbe94ec2015-09-09 14:52:59 -0700978 animationHandler.addAnimationFrameCallback(this, (long) (mStartDelay * sDurationScale));
Doris Liuf57bfe22015-10-01 13:26:01 -0700979
George Mount907c1772016-03-24 16:29:03 -0700980 if (mStartDelay == 0 || mSeekFraction >= 0) {
Doris Liuf57bfe22015-10-01 13:26:01 -0700981 // If there's no start delay, init the animation and notify start listeners right away
Doris Liufbe94ec2015-09-09 14:52:59 -0700982 // to be consistent with the previous behavior. Otherwise, postpone this until the first
983 // frame after the start delay.
Doris Liuf57bfe22015-10-01 13:26:01 -0700984 startAnimation();
Doris Liub199da72016-02-25 14:23:09 -0800985 if (mSeekFraction == -1) {
986 // No seek, start at play time 0. Note that the reason we are not using fraction 0
987 // is because for animations with 0 duration, we want to be consistent with pre-N
988 // behavior: skip to the final value immediately.
989 setCurrentPlayTime(0);
990 } else {
991 setCurrentFraction(mSeekFraction);
992 }
Doris Liuf57bfe22015-10-01 13:26:01 -0700993 }
Chet Haasea18a86b2010-09-07 13:20:00 -0700994 }
995
996 @Override
997 public void start() {
998 start(false);
999 }
1000
1001 @Override
1002 public void cancel() {
Doris Liu3618d302015-08-14 11:11:08 -07001003 if (Looper.myLooper() == null) {
1004 throw new AndroidRuntimeException("Animators may only be run on Looper threads");
1005 }
Doris Liu3dbaae12015-08-27 14:56:30 -07001006
1007 // If end has already been requested, through a previous end() or cancel() call, no-op
1008 // until animation starts again.
1009 if (mAnimationEndRequested) {
1010 return;
1011 }
1012
Chet Haase2970c492010-11-09 13:58:04 -08001013 // Only cancel if the animation is actually running or has been started and is about
1014 // to run
Doris Liu3618d302015-08-14 11:11:08 -07001015 // Only notify listeners if the animator has actually started
1016 if ((mStarted || mRunning) && mListeners != null) {
1017 if (!mRunning) {
1018 // If it's not yet running, then start listeners weren't called. Call them now.
1019 notifyStartListeners();
Chet Haase7dfacdb2011-07-11 17:01:56 -07001020 }
Doris Liu3618d302015-08-14 11:11:08 -07001021 ArrayList<AnimatorListener> tmpListeners =
1022 (ArrayList<AnimatorListener>) mListeners.clone();
1023 for (AnimatorListener listener : tmpListeners) {
1024 listener.onAnimationCancel(this);
1025 }
Chet Haase2970c492010-11-09 13:58:04 -08001026 }
Doris Liu3618d302015-08-14 11:11:08 -07001027 endAnimation();
1028
Chet Haasea18a86b2010-09-07 13:20:00 -07001029 }
1030
1031 @Override
1032 public void end() {
Doris Liu3618d302015-08-14 11:11:08 -07001033 if (Looper.myLooper() == null) {
1034 throw new AndroidRuntimeException("Animators may only be run on Looper threads");
1035 }
1036 if (!mRunning) {
Chet Haasea18a86b2010-09-07 13:20:00 -07001037 // Special case if the animation has not yet started; get it ready for ending
Doris Liu3618d302015-08-14 11:11:08 -07001038 startAnimation();
Chet Haase17cf42c2012-04-17 13:18:14 -07001039 mStarted = true;
Chet Haaseadd65772011-02-09 16:47:29 -08001040 } else if (!mInitialized) {
1041 initAnimation();
Chet Haasea18a86b2010-09-07 13:20:00 -07001042 }
Doris Liufbe94ec2015-09-09 14:52:59 -07001043 animateValue(shouldPlayBackward(mRepeatCount) ? 0f : 1f);
Doris Liu3618d302015-08-14 11:11:08 -07001044 endAnimation();
Chet Haasea18a86b2010-09-07 13:20:00 -07001045 }
1046
1047 @Override
Chet Haase8aa1ffb2013-08-08 14:00:00 -07001048 public void resume() {
George Mounta06b3f12016-03-02 08:06:32 -08001049 if (Looper.myLooper() == null) {
1050 throw new AndroidRuntimeException("Animators may only be resumed from the same " +
1051 "thread that the animator was started on");
1052 }
1053 if (mPaused && !mResumed) {
Chet Haase8aa1ffb2013-08-08 14:00:00 -07001054 mResumed = true;
George Mounta06b3f12016-03-02 08:06:32 -08001055 if (mPauseTime > 0) {
1056 AnimationHandler handler = AnimationHandler.getInstance();
1057 handler.addAnimationFrameCallback(this, 0);
1058 }
Chet Haase8aa1ffb2013-08-08 14:00:00 -07001059 }
1060 super.resume();
1061 }
1062
1063 @Override
1064 public void pause() {
1065 boolean previouslyPaused = mPaused;
1066 super.pause();
1067 if (!previouslyPaused && mPaused) {
1068 mPauseTime = -1;
1069 mResumed = false;
1070 }
1071 }
1072
1073 @Override
Chet Haasea18a86b2010-09-07 13:20:00 -07001074 public boolean isRunning() {
Doris Liu3618d302015-08-14 11:11:08 -07001075 return mRunning;
Chet Haase8b699792011-08-05 15:20:19 -07001076 }
1077
1078 @Override
1079 public boolean isStarted() {
1080 return mStarted;
Chet Haasea18a86b2010-09-07 13:20:00 -07001081 }
1082
1083 /**
1084 * Plays the ValueAnimator in reverse. If the animation is already running,
1085 * it will stop itself and play backwards from the point reached when reverse was called.
1086 * If the animation is not currently running, then it will start from the end and
1087 * play backwards. This behavior is only set for the current animation; future playing
1088 * of the animation will use the default behavior of playing forward.
1089 */
ztenghui7bc6a3f2014-07-15 15:12:12 -07001090 @Override
Chet Haasea18a86b2010-09-07 13:20:00 -07001091 public void reverse() {
Doris Liu3618d302015-08-14 11:11:08 -07001092 if (mRunning) {
Chet Haasea18a86b2010-09-07 13:20:00 -07001093 long currentTime = AnimationUtils.currentAnimationTimeMillis();
1094 long currentPlayTime = currentTime - mStartTime;
Doris Liufbe94ec2015-09-09 14:52:59 -07001095 long timeLeft = getScaledDuration() - currentPlayTime;
Chet Haasea18a86b2010-09-07 13:20:00 -07001096 mStartTime = currentTime - timeLeft;
Jeff Brownc42b28d2015-04-06 19:49:02 -07001097 mStartTimeCommitted = true; // do not allow start time to be compensated for jank
Chet Haasef4e3bab2014-12-02 17:51:34 -08001098 mReversing = !mReversing;
Chet Haasef43fb2a2013-09-06 07:59:36 -07001099 } else if (mStarted) {
1100 end();
Chet Haasea18a86b2010-09-07 13:20:00 -07001101 } else {
1102 start(true);
1103 }
1104 }
1105
1106 /**
ztenghui7bc6a3f2014-07-15 15:12:12 -07001107 * @hide
1108 */
1109 @Override
1110 public boolean canReverse() {
1111 return true;
1112 }
1113
1114 /**
Chet Haasea18a86b2010-09-07 13:20:00 -07001115 * Called internally to end an animation by removing it from the animations list. Must be
1116 * called on the UI thread.
1117 */
Doris Liu3dbaae12015-08-27 14:56:30 -07001118 private void endAnimation() {
1119 if (mAnimationEndRequested) {
1120 return;
1121 }
Doris Liu3618d302015-08-14 11:11:08 -07001122 AnimationHandler handler = AnimationHandler.getInstance();
1123 handler.removeCallback(this);
Doris Liu3dbaae12015-08-27 14:56:30 -07001124
1125 mAnimationEndRequested = true;
Chet Haase8aa1ffb2013-08-08 14:00:00 -07001126 mPaused = false;
Chet Haase17cf42c2012-04-17 13:18:14 -07001127 if ((mStarted || mRunning) && mListeners != null) {
1128 if (!mRunning) {
1129 // If it's not yet running, then start listeners weren't called. Call them now.
1130 notifyStartListeners();
1131 }
Chet Haasea18a86b2010-09-07 13:20:00 -07001132 ArrayList<AnimatorListener> tmpListeners =
1133 (ArrayList<AnimatorListener>) mListeners.clone();
Chet Haase7c608f22010-10-22 17:54:04 -07001134 int numListeners = tmpListeners.size();
1135 for (int i = 0; i < numListeners; ++i) {
1136 tmpListeners.get(i).onAnimationEnd(this);
Chet Haasea18a86b2010-09-07 13:20:00 -07001137 }
1138 }
Chet Haase8b699792011-08-05 15:20:19 -07001139 mRunning = false;
Chet Haaseb8f574a2011-08-03 14:10:06 -07001140 mStarted = false;
Chet Haase17cf42c2012-04-17 13:18:14 -07001141 mStartListenersCalled = false;
Chet Haasef4e3bab2014-12-02 17:51:34 -08001142 mReversing = false;
Doris Liuf57bfe22015-10-01 13:26:01 -07001143 mLastFrameTime = 0;
Chet Haase9b80ca82013-06-04 09:37:38 -07001144 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
1145 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, getNameForTrace(),
1146 System.identityHashCode(this));
1147 }
Chet Haasea18a86b2010-09-07 13:20:00 -07001148 }
1149
1150 /**
1151 * Called internally to start an animation by adding it to the active animations list. Must be
1152 * called on the UI thread.
1153 */
Doris Liu3618d302015-08-14 11:11:08 -07001154 private void startAnimation() {
Chet Haase9b80ca82013-06-04 09:37:38 -07001155 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
1156 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, getNameForTrace(),
1157 System.identityHashCode(this));
1158 }
Doris Liu66d48562015-11-09 14:44:35 -08001159
1160 mAnimationEndRequested = false;
Chet Haasea18a86b2010-09-07 13:20:00 -07001161 initAnimation();
Doris Liu3618d302015-08-14 11:11:08 -07001162 mRunning = true;
Doris Liufbe94ec2015-09-09 14:52:59 -07001163 if (mSeekFraction >= 0) {
1164 mOverallFraction = mSeekFraction;
1165 } else {
1166 mOverallFraction = 0f;
1167 }
Doris Liu3618d302015-08-14 11:11:08 -07001168 if (mListeners != null) {
Chet Haase17cf42c2012-04-17 13:18:14 -07001169 notifyStartListeners();
Chet Haasea18a86b2010-09-07 13:20:00 -07001170 }
1171 }
1172
1173 /**
Chet Haasefdd3ad72013-04-24 16:38:20 -07001174 * Returns the name of this animator for debugging purposes.
1175 */
1176 String getNameForTrace() {
1177 return "animator";
1178 }
1179
Chet Haasea18a86b2010-09-07 13:20:00 -07001180 /**
Jeff Brownc42b28d2015-04-06 19:49:02 -07001181 * Applies an adjustment to the animation to compensate for jank between when
1182 * the animation first ran and when the frame was drawn.
Doris Liu3618d302015-08-14 11:11:08 -07001183 * @hide
Jeff Brownc42b28d2015-04-06 19:49:02 -07001184 */
Doris Liu3618d302015-08-14 11:11:08 -07001185 public void commitAnimationFrame(long frameTime) {
Jeff Brownc42b28d2015-04-06 19:49:02 -07001186 if (!mStartTimeCommitted) {
1187 mStartTimeCommitted = true;
Doris Liu3618d302015-08-14 11:11:08 -07001188 long adjustment = frameTime - mLastFrameTime;
1189 if (adjustment > 0) {
Jeff Brownc42b28d2015-04-06 19:49:02 -07001190 mStartTime += adjustment;
1191 if (DEBUG) {
1192 Log.d(TAG, "Adjusted start time by " + adjustment + " ms: " + toString());
1193 }
1194 }
1195 }
1196 }
1197
1198 /**
Chet Haasea18a86b2010-09-07 13:20:00 -07001199 * This internal function processes a single animation frame for a given animation. The
1200 * currentTime parameter is the timing pulse sent by the handler, used to calculate the
1201 * elapsed duration, and therefore
1202 * the elapsed fraction, of the animation. The return value indicates whether the animation
1203 * should be ended (which happens when the elapsed time of the animation exceeds the
1204 * animation's duration, including the repeatCount).
1205 *
1206 * @param currentTime The current time, as tracked by the static timing handler
1207 * @return true if the animation's duration, including any repetitions due to
Doris Liu3618d302015-08-14 11:11:08 -07001208 * <code>repeatCount</code> has been exceeded and the animation should be ended.
Chet Haasea18a86b2010-09-07 13:20:00 -07001209 */
Doris Liu3618d302015-08-14 11:11:08 -07001210 boolean animateBasedOnTime(long currentTime) {
Chet Haasea18a86b2010-09-07 13:20:00 -07001211 boolean done = false;
Doris Liu3618d302015-08-14 11:11:08 -07001212 if (mRunning) {
Doris Liu56b0b572016-04-13 14:13:49 -07001213 final long scaledDuration = getScaledDuration();
1214 final float fraction = scaledDuration > 0 ?
1215 (float)(currentTime - mStartTime) / scaledDuration : 1f;
Doris Liufbe94ec2015-09-09 14:52:59 -07001216 final float lastFraction = mOverallFraction;
1217 final boolean newIteration = (int) fraction > (int) lastFraction;
1218 final boolean lastIterationFinished = (fraction >= mRepeatCount + 1) &&
1219 (mRepeatCount != INFINITE);
Doris Liu56b0b572016-04-13 14:13:49 -07001220 if (scaledDuration == 0) {
1221 // 0 duration animator, ignore the repeat count and skip to the end
1222 done = true;
1223 } else if (newIteration && !lastIterationFinished) {
Doris Liufbe94ec2015-09-09 14:52:59 -07001224 // Time to repeat
1225 if (mListeners != null) {
1226 int numListeners = mListeners.size();
1227 for (int i = 0; i < numListeners; ++i) {
1228 mListeners.get(i).onAnimationRepeat(this);
Chet Haasea18a86b2010-09-07 13:20:00 -07001229 }
Chet Haasea18a86b2010-09-07 13:20:00 -07001230 }
Doris Liufbe94ec2015-09-09 14:52:59 -07001231 } else if (lastIterationFinished) {
1232 done = true;
Chet Haasea18a86b2010-09-07 13:20:00 -07001233 }
Doris Liufbe94ec2015-09-09 14:52:59 -07001234 mOverallFraction = clampFraction(fraction);
1235 float currentIterationFraction = getCurrentIterationFraction(mOverallFraction);
1236 animateValue(currentIterationFraction);
Chet Haasea18a86b2010-09-07 13:20:00 -07001237 }
Chet Haasea18a86b2010-09-07 13:20:00 -07001238 return done;
1239 }
1240
1241 /**
Jeff Brown20c4f872012-04-26 17:38:21 -07001242 * Processes a frame of the animation, adjusting the start time if needed.
1243 *
1244 * @param frameTime The frame time.
1245 * @return true if the animation has ended.
Doris Liu3618d302015-08-14 11:11:08 -07001246 * @hide
Jeff Brown20c4f872012-04-26 17:38:21 -07001247 */
Doris Liu3618d302015-08-14 11:11:08 -07001248 public final void doAnimationFrame(long frameTime) {
Doris Liu3618d302015-08-14 11:11:08 -07001249 AnimationHandler handler = AnimationHandler.getInstance();
Doris Liuf57bfe22015-10-01 13:26:01 -07001250 if (mLastFrameTime == 0) {
Doris Liu3618d302015-08-14 11:11:08 -07001251 // First frame
1252 handler.addOneShotCommitCallback(this);
Doris Liuf57bfe22015-10-01 13:26:01 -07001253 if (mStartDelay > 0) {
1254 startAnimation();
1255 }
Chet Haase0d1c27a2014-11-03 18:35:16 +00001256 if (mSeekFraction < 0) {
Jeff Brown20c4f872012-04-26 17:38:21 -07001257 mStartTime = frameTime;
1258 } else {
Doris Liufbe94ec2015-09-09 14:52:59 -07001259 long seekTime = (long) (getScaledDuration() * mSeekFraction);
Chet Haase0d1c27a2014-11-03 18:35:16 +00001260 mStartTime = frameTime - seekTime;
1261 mSeekFraction = -1;
Jeff Brown20c4f872012-04-26 17:38:21 -07001262 }
Jeff Brownc42b28d2015-04-06 19:49:02 -07001263 mStartTimeCommitted = false; // allow start time to be compensated for jank
Jeff Brown20c4f872012-04-26 17:38:21 -07001264 }
Doris Liuf57bfe22015-10-01 13:26:01 -07001265 mLastFrameTime = frameTime;
Chet Haase8aa1ffb2013-08-08 14:00:00 -07001266 if (mPaused) {
George Mounta06b3f12016-03-02 08:06:32 -08001267 mPauseTime = frameTime;
1268 handler.removeCallback(this);
Doris Liu3618d302015-08-14 11:11:08 -07001269 return;
Chet Haase8aa1ffb2013-08-08 14:00:00 -07001270 } else if (mResumed) {
1271 mResumed = false;
1272 if (mPauseTime > 0) {
1273 // Offset by the duration that the animation was paused
1274 mStartTime += (frameTime - mPauseTime);
Jeff Brownc42b28d2015-04-06 19:49:02 -07001275 mStartTimeCommitted = false; // allow start time to be compensated for jank
Chet Haase8aa1ffb2013-08-08 14:00:00 -07001276 }
Doris Liu3618d302015-08-14 11:11:08 -07001277 handler.addOneShotCommitCallback(this);
Chet Haase8aa1ffb2013-08-08 14:00:00 -07001278 }
Jeff Brown20c4f872012-04-26 17:38:21 -07001279 // The frame time might be before the start time during the first frame of
1280 // an animation. The "current time" must always be on or after the start
1281 // time to avoid animating frames at negative time intervals. In practice, this
1282 // is very rare and only happens when seeking backwards.
1283 final long currentTime = Math.max(frameTime, mStartTime);
Doris Liu3618d302015-08-14 11:11:08 -07001284 boolean finished = animateBasedOnTime(currentTime);
1285
1286 if (finished) {
1287 endAnimation();
1288 }
Jeff Brown20c4f872012-04-26 17:38:21 -07001289 }
1290
1291 /**
Chet Haasea00f3862011-02-22 06:34:40 -08001292 * Returns the current animation fraction, which is the elapsed/interpolated fraction used in
1293 * the most recent frame update on the animation.
1294 *
1295 * @return Elapsed/interpolated fraction of the animation.
1296 */
1297 public float getAnimatedFraction() {
1298 return mCurrentFraction;
1299 }
1300
1301 /**
Chet Haasea18a86b2010-09-07 13:20:00 -07001302 * This method is called with the elapsed fraction of the animation during every
1303 * animation frame. This function turns the elapsed fraction into an interpolated fraction
1304 * and then into an animated value (from the evaluator. The function is called mostly during
1305 * animation updates, but it is also called when the <code>end()</code>
1306 * function is called, to set the final value on the property.
1307 *
1308 * <p>Overrides of this method must call the superclass to perform the calculation
1309 * of the animated value.</p>
1310 *
1311 * @param fraction The elapsed fraction of the animation.
1312 */
Tor Norbyec615c6f2015-03-02 10:11:44 -08001313 @CallSuper
Chet Haasea18a86b2010-09-07 13:20:00 -07001314 void animateValue(float fraction) {
1315 fraction = mInterpolator.getInterpolation(fraction);
Chet Haasea00f3862011-02-22 06:34:40 -08001316 mCurrentFraction = fraction;
Chet Haasea18a86b2010-09-07 13:20:00 -07001317 int numValues = mValues.length;
1318 for (int i = 0; i < numValues; ++i) {
1319 mValues[i].calculateValue(fraction);
1320 }
1321 if (mUpdateListeners != null) {
1322 int numListeners = mUpdateListeners.size();
1323 for (int i = 0; i < numListeners; ++i) {
1324 mUpdateListeners.get(i).onAnimationUpdate(this);
1325 }
1326 }
1327 }
1328
1329 @Override
1330 public ValueAnimator clone() {
1331 final ValueAnimator anim = (ValueAnimator) super.clone();
1332 if (mUpdateListeners != null) {
Yigit Boyard422dc32014-09-25 12:23:35 -07001333 anim.mUpdateListeners = new ArrayList<AnimatorUpdateListener>(mUpdateListeners);
Chet Haasea18a86b2010-09-07 13:20:00 -07001334 }
Chet Haase0d1c27a2014-11-03 18:35:16 +00001335 anim.mSeekFraction = -1;
Chet Haasef4e3bab2014-12-02 17:51:34 -08001336 anim.mReversing = false;
Chet Haasea18a86b2010-09-07 13:20:00 -07001337 anim.mInitialized = false;
ztenghui26e9a192015-04-10 13:14:17 -07001338 anim.mStarted = false;
1339 anim.mRunning = false;
1340 anim.mPaused = false;
1341 anim.mResumed = false;
1342 anim.mStartListenersCalled = false;
ztenghuie1b5c2b2015-04-21 14:17:00 -07001343 anim.mStartTime = 0;
1344 anim.mStartTimeCommitted = false;
Doris Liu3dbaae12015-08-27 14:56:30 -07001345 anim.mAnimationEndRequested = false;
ztenghuie1b5c2b2015-04-21 14:17:00 -07001346 anim.mPauseTime = 0;
Doris Liu3618d302015-08-14 11:11:08 -07001347 anim.mLastFrameTime = 0;
Doris Liufbe94ec2015-09-09 14:52:59 -07001348 anim.mOverallFraction = 0;
ztenghuie1b5c2b2015-04-21 14:17:00 -07001349 anim.mCurrentFraction = 0;
ztenghui26e9a192015-04-10 13:14:17 -07001350
Chet Haasea18a86b2010-09-07 13:20:00 -07001351 PropertyValuesHolder[] oldValues = mValues;
1352 if (oldValues != null) {
1353 int numValues = oldValues.length;
1354 anim.mValues = new PropertyValuesHolder[numValues];
Chet Haasea18a86b2010-09-07 13:20:00 -07001355 anim.mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
1356 for (int i = 0; i < numValues; ++i) {
Chet Haased4dd7022011-04-04 15:25:09 -07001357 PropertyValuesHolder newValuesHolder = oldValues[i].clone();
1358 anim.mValues[i] = newValuesHolder;
1359 anim.mValuesMap.put(newValuesHolder.getPropertyName(), newValuesHolder);
Chet Haasea18a86b2010-09-07 13:20:00 -07001360 }
1361 }
1362 return anim;
1363 }
1364
1365 /**
1366 * Implementors of this interface can add themselves as update listeners
1367 * to an <code>ValueAnimator</code> instance to receive callbacks on every animation
1368 * frame, after the current frame's values have been calculated for that
1369 * <code>ValueAnimator</code>.
1370 */
1371 public static interface AnimatorUpdateListener {
1372 /**
1373 * <p>Notifies the occurrence of another frame of the animation.</p>
1374 *
1375 * @param animation The animation which was repeated.
1376 */
1377 void onAnimationUpdate(ValueAnimator animation);
1378
1379 }
Brad Fitzpatrick599ca292010-10-22 14:47:03 -07001380
1381 /**
1382 * Return the number of animations currently running.
1383 *
Jeff Brown9c38dbe2011-12-02 16:22:46 -08001384 * Used by StrictMode internally to annotate violations.
1385 * May be called on arbitrary threads!
Brad Fitzpatrick599ca292010-10-22 14:47:03 -07001386 *
1387 * @hide
1388 */
1389 public static int getCurrentAnimationsCount() {
Doris Liu3618d302015-08-14 11:11:08 -07001390 return AnimationHandler.getAnimationCount();
Patrick Dubroy8901ffa2011-01-16 17:13:55 -08001391 }
Chet Haasee9140a72011-02-16 16:23:29 -08001392
1393 @Override
1394 public String toString() {
1395 String returnVal = "ValueAnimator@" + Integer.toHexString(hashCode());
1396 if (mValues != null) {
1397 for (int i = 0; i < mValues.length; ++i) {
1398 returnVal += "\n " + mValues[i].toString();
1399 }
1400 }
1401 return returnVal;
1402 }
John Reckd3de42c2014-07-15 14:29:33 -07001403
1404 /**
1405 * <p>Whether or not the ValueAnimator is allowed to run asynchronously off of
1406 * the UI thread. This is a hint that informs the ValueAnimator that it is
1407 * OK to run the animation off-thread, however ValueAnimator may decide
1408 * that it must run the animation on the UI thread anyway. For example if there
1409 * is an {@link AnimatorUpdateListener} the animation will run on the UI thread,
1410 * regardless of the value of this hint.</p>
1411 *
1412 * <p>Regardless of whether or not the animation runs asynchronously, all
1413 * listener callbacks will be called on the UI thread.</p>
1414 *
1415 * <p>To be able to use this hint the following must be true:</p>
1416 * <ol>
1417 * <li>{@link #getAnimatedFraction()} is not needed (it will return undefined values).</li>
1418 * <li>The animator is immutable while {@link #isStarted()} is true. Requests
1419 * to change values, duration, delay, etc... may be ignored.</li>
1420 * <li>Lifecycle callback events may be asynchronous. Events such as
1421 * {@link Animator.AnimatorListener#onAnimationEnd(Animator)} or
1422 * {@link Animator.AnimatorListener#onAnimationRepeat(Animator)} may end up delayed
1423 * as they must be posted back to the UI thread, and any actions performed
1424 * by those callbacks (such as starting new animations) will not happen
1425 * in the same frame.</li>
1426 * <li>State change requests ({@link #cancel()}, {@link #end()}, {@link #reverse()}, etc...)
1427 * may be asynchronous. It is guaranteed that all state changes that are
1428 * performed on the UI thread in the same frame will be applied as a single
1429 * atomic update, however that frame may be the current frame,
1430 * the next frame, or some future frame. This will also impact the observed
1431 * state of the Animator. For example, {@link #isStarted()} may still return true
1432 * after a call to {@link #end()}. Using the lifecycle callbacks is preferred over
1433 * queries to {@link #isStarted()}, {@link #isRunning()}, and {@link #isPaused()}
1434 * for this reason.</li>
1435 * </ol>
1436 * @hide
1437 */
John Reckc01bd112014-07-18 16:22:09 -07001438 @Override
John Reckd3de42c2014-07-15 14:29:33 -07001439 public void setAllowRunningAsynchronously(boolean mayRunAsync) {
1440 // It is up to subclasses to support this, if they can.
1441 }
Brad Fitzpatrick599ca292010-10-22 14:47:03 -07001442}