• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package android.animation;
18 
19 import android.os.Looper;
20 import android.os.Trace;
21 import android.util.AndroidRuntimeException;
22 import android.view.Choreographer;
23 import android.view.animation.AccelerateDecelerateInterpolator;
24 import android.view.animation.AnimationUtils;
25 import android.view.animation.LinearInterpolator;
26 
27 import java.util.ArrayList;
28 import 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
40  * {@link ValueAnimator#setInterpolator(TimeInterpolator)}.</p>
41  *
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>
48  */
49 @SuppressWarnings("unchecked")
50 public class ValueAnimator extends Animator {
51 
52     /**
53      * Internal constants
54      */
55     private static float sDurationScale = 1.0f;
56 
57     /**
58      * Values used with internal variable mPlayingState to indicate the current state of an
59      * animation.
60      */
61     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
64 
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()
75     long mStartTime;
76 
77     /**
78      * Set when setCurrentPlayTime() is called. If negative, animation is not currently seeked
79      * to a value.
80      */
81     long mSeekTime = -1;
82 
83     /**
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 
97     // The static sAnimationHandler processes the internal timing loop on which all animations
98     // are based
99     /**
100      * @hide
101      */
102     protected static ThreadLocal<AnimationHandler> sAnimationHandler =
103             new ThreadLocal<AnimationHandler>();
104 
105     // The time interpolator to be used if none is set on the animation
106     private static final TimeInterpolator sDefaultInterpolator =
107             new AccelerateDecelerateInterpolator();
108 
109     /**
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     /**
122      * Tracks current elapsed/eased fraction, for querying in getAnimatedFraction().
123      */
124     private float mCurrentFraction = 0f;
125 
126     /**
127      * 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
143      * STOPPED, RUNNING, SEEKED.
144      */
145     int mPlayingState = STOPPED;
146 
147     /**
148      * 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      */
155     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      */
161     private boolean mStarted = false;
162 
163     /**
164      * Tracks whether we've notified listeners of the onAnimationStart() event. This can be
165      * 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     /**
171      * 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
181     private long mDuration = (long)(300 * sDurationScale);
182     private long mUnscaledDuration = 300;
183 
184     // The amount of time in ms to delay starting the animation after start() is called
185     private long mStartDelay = 0;
186     private long mUnscaledStartDelay = 0;
187 
188     // 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      */
204     private TimeInterpolator mInterpolator = sDefaultInterpolator;
205 
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 
242 
243     /**
244      * @hide
245      */
setDurationScale(float durationScale)246     public static void setDurationScale(float durationScale) {
247         sDurationScale = durationScale;
248     }
249 
250     /**
251      * @hide
252      */
getDurationScale()253     public static float getDurationScale() {
254         return sDurationScale;
255     }
256 
257     /**
258      * Creates a new ValueAnimator object. This default constructor is primarily for
259      * use internally; the factory methods which take parameters are more generally
260      * useful.
261      */
ValueAnimator()262     public ValueAnimator() {
263     }
264 
265     /**
266      * 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.
272      *
273      * @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.
275      */
ofInt(int... values)276     public static ValueAnimator ofInt(int... values) {
277         ValueAnimator anim = new ValueAnimator();
278         anim.setIntValues(values);
279         return anim;
280     }
281 
282     /**
283      * Constructs and returns a ValueAnimator that animates between float values. A single
284      * value implies that that value is the one being animated to. However, this is not typically
285      * useful in a ValueAnimator object because there is no way for the object to determine the
286      * starting value for the animation (unlike ObjectAnimator, which can derive that value
287      * from the target object and property being animated). Therefore, there should typically
288      * be two or more values.
289      *
290      * @param values A set of values that the animation will animate between over time.
291      * @return A ValueAnimator object that is set up to animate between the given values.
292      */
ofFloat(float... values)293     public static ValueAnimator ofFloat(float... values) {
294         ValueAnimator anim = new ValueAnimator();
295         anim.setFloatValues(values);
296         return anim;
297     }
298 
299     /**
300      * Constructs and returns a ValueAnimator that animates between the values
301      * specified in the PropertyValuesHolder objects.
302      *
303      * @param values A set of PropertyValuesHolder objects whose values will be animated
304      * between over time.
305      * @return A ValueAnimator object that is set up to animate between the given values.
306      */
ofPropertyValuesHolder(PropertyValuesHolder... values)307     public static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values) {
308         ValueAnimator anim = new ValueAnimator();
309         anim.setValues(values);
310         return anim;
311     }
312     /**
313      * Constructs and returns a ValueAnimator that animates between Object values. A single
314      * value implies that that value is the one being animated to. However, this is not typically
315      * useful in a ValueAnimator object because there is no way for the object to determine the
316      * starting value for the animation (unlike ObjectAnimator, which can derive that value
317      * from the target object and property being animated). Therefore, there should typically
318      * be two or more values.
319      *
320      * <p>Since ValueAnimator does not know how to animate between arbitrary Objects, this
321      * factory method also takes a TypeEvaluator object that the ValueAnimator will use
322      * to perform that interpolation.
323      *
324      * @param evaluator A TypeEvaluator that will be called on each animation frame to
325      * provide the ncessry interpolation between the Object values to derive the animated
326      * value.
327      * @param values A set of values that the animation will animate between over time.
328      * @return A ValueAnimator object that is set up to animate between the given values.
329      */
ofObject(TypeEvaluator evaluator, Object... values)330     public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values) {
331         ValueAnimator anim = new ValueAnimator();
332         anim.setObjectValues(values);
333         anim.setEvaluator(evaluator);
334         return anim;
335     }
336 
337     /**
338      * Sets int values that will be animated between. A single
339      * value implies that that value is the one being animated to. However, this is not typically
340      * useful in a ValueAnimator object because there is no way for the object to determine the
341      * starting value for the animation (unlike ObjectAnimator, which can derive that value
342      * from the target object and property being animated). Therefore, there should typically
343      * be two or more values.
344      *
345      * <p>If there are already multiple sets of values defined for this ValueAnimator via more
346      * than one PropertyValuesHolder object, this method will set the values for the first
347      * of those objects.</p>
348      *
349      * @param values A set of values that the animation will animate between over time.
350      */
setIntValues(int... values)351     public void setIntValues(int... values) {
352         if (values == null || values.length == 0) {
353             return;
354         }
355         if (mValues == null || mValues.length == 0) {
356             setValues(PropertyValuesHolder.ofInt("", values));
357         } else {
358             PropertyValuesHolder valuesHolder = mValues[0];
359             valuesHolder.setIntValues(values);
360         }
361         // New property/values/target should cause re-initialization prior to starting
362         mInitialized = false;
363     }
364 
365     /**
366      * Sets float values that will be animated between. A single
367      * value implies that that value is the one being animated to. However, this is not typically
368      * useful in a ValueAnimator object because there is no way for the object to determine the
369      * starting value for the animation (unlike ObjectAnimator, which can derive that value
370      * from the target object and property being animated). Therefore, there should typically
371      * be two or more values.
372      *
373      * <p>If there are already multiple sets of values defined for this ValueAnimator via more
374      * than one PropertyValuesHolder object, this method will set the values for the first
375      * of those objects.</p>
376      *
377      * @param values A set of values that the animation will animate between over time.
378      */
setFloatValues(float... values)379     public void setFloatValues(float... values) {
380         if (values == null || values.length == 0) {
381             return;
382         }
383         if (mValues == null || mValues.length == 0) {
384             setValues(PropertyValuesHolder.ofFloat("", values));
385         } else {
386             PropertyValuesHolder valuesHolder = mValues[0];
387             valuesHolder.setFloatValues(values);
388         }
389         // New property/values/target should cause re-initialization prior to starting
390         mInitialized = false;
391     }
392 
393     /**
394      * Sets the values to animate between for this animation. A single
395      * value implies that that value is the one being animated to. However, this is not typically
396      * useful in a ValueAnimator object because there is no way for the object to determine the
397      * starting value for the animation (unlike ObjectAnimator, which can derive that value
398      * from the target object and property being animated). Therefore, there should typically
399      * be two or more values.
400      *
401      * <p>If there are already multiple sets of values defined for this ValueAnimator via more
402      * than one PropertyValuesHolder object, this method will set the values for the first
403      * of those objects.</p>
404      *
405      * <p>There should be a TypeEvaluator set on the ValueAnimator that knows how to interpolate
406      * between these value objects. ValueAnimator only knows how to interpolate between the
407      * primitive types specified in the other setValues() methods.</p>
408      *
409      * @param values The set of values to animate between.
410      */
setObjectValues(Object... values)411     public void setObjectValues(Object... values) {
412         if (values == null || values.length == 0) {
413             return;
414         }
415         if (mValues == null || mValues.length == 0) {
416             setValues(PropertyValuesHolder.ofObject("", null, values));
417         } else {
418             PropertyValuesHolder valuesHolder = mValues[0];
419             valuesHolder.setObjectValues(values);
420         }
421         // New property/values/target should cause re-initialization prior to starting
422         mInitialized = false;
423     }
424 
425     /**
426      * Sets the values, per property, being animated between. This function is called internally
427      * by the constructors of ValueAnimator that take a list of values. But a ValueAnimator can
428      * be constructed without values and this method can be called to set the values manually
429      * instead.
430      *
431      * @param values The set of values, per property, being animated between.
432      */
setValues(PropertyValuesHolder... values)433     public void setValues(PropertyValuesHolder... values) {
434         int numValues = values.length;
435         mValues = values;
436         mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
437         for (int i = 0; i < numValues; ++i) {
438             PropertyValuesHolder valuesHolder = values[i];
439             mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);
440         }
441         // New property/values/target should cause re-initialization prior to starting
442         mInitialized = false;
443     }
444 
445     /**
446      * Returns the values that this ValueAnimator animates between. These values are stored in
447      * PropertyValuesHolder objects, even if the ValueAnimator was created with a simple list
448      * of value objects instead.
449      *
450      * @return PropertyValuesHolder[] An array of PropertyValuesHolder objects which hold the
451      * values, per property, that define the animation.
452      */
getValues()453     public PropertyValuesHolder[] getValues() {
454         return mValues;
455     }
456 
457     /**
458      * This function is called immediately before processing the first animation
459      * frame of an animation. If there is a nonzero <code>startDelay</code>, the
460      * function is called after that delay ends.
461      * It takes care of the final initialization steps for the
462      * animation.
463      *
464      *  <p>Overrides of this method should call the superclass method to ensure
465      *  that internal mechanisms for the animation are set up correctly.</p>
466      */
initAnimation()467     void initAnimation() {
468         if (!mInitialized) {
469             int numValues = mValues.length;
470             for (int i = 0; i < numValues; ++i) {
471                 mValues[i].init();
472             }
473             mInitialized = true;
474         }
475     }
476 
477 
478     /**
479      * Sets the length of the animation. The default duration is 300 milliseconds.
480      *
481      * @param duration The length of the animation, in milliseconds. This value cannot
482      * be negative.
483      * @return ValueAnimator The object called with setDuration(). This return
484      * value makes it easier to compose statements together that construct and then set the
485      * duration, as in <code>ValueAnimator.ofInt(0, 10).setDuration(500).start()</code>.
486      */
setDuration(long duration)487     public ValueAnimator setDuration(long duration) {
488         if (duration < 0) {
489             throw new IllegalArgumentException("Animators cannot have negative duration: " +
490                     duration);
491         }
492         mUnscaledDuration = duration;
493         mDuration = (long)(duration * sDurationScale);
494         return this;
495     }
496 
497     /**
498      * Gets the length of the animation. The default duration is 300 milliseconds.
499      *
500      * @return The length of the animation, in milliseconds.
501      */
getDuration()502     public long getDuration() {
503         return mUnscaledDuration;
504     }
505 
506     /**
507      * Sets the position of the animation to the specified point in time. This time should
508      * be between 0 and the total duration of the animation, including any repetition. If
509      * the animation has not yet been started, then it will not advance forward after it is
510      * set to this time; it will simply set the time to this value and perform any appropriate
511      * actions based on that time. If the animation is already running, then setCurrentPlayTime()
512      * will set the current playing time to this value and continue playing from that point.
513      *
514      * @param playTime The time, in milliseconds, to which the animation is advanced or rewound.
515      */
setCurrentPlayTime(long playTime)516     public void setCurrentPlayTime(long playTime) {
517         initAnimation();
518         long currentTime = AnimationUtils.currentAnimationTimeMillis();
519         if (mPlayingState != RUNNING) {
520             mSeekTime = playTime;
521             mPlayingState = SEEKED;
522         }
523         mStartTime = currentTime - playTime;
524         doAnimationFrame(currentTime);
525     }
526 
527     /**
528      * Gets the current position of the animation in time, which is equal to the current
529      * time minus the time that the animation started. An animation that is not yet started will
530      * return a value of zero.
531      *
532      * @return The current position in time of the animation.
533      */
getCurrentPlayTime()534     public long getCurrentPlayTime() {
535         if (!mInitialized || mPlayingState == STOPPED) {
536             return 0;
537         }
538         return AnimationUtils.currentAnimationTimeMillis() - mStartTime;
539     }
540 
541     /**
542      * This custom, static handler handles the timing pulse that is shared by
543      * all active animations. This approach ensures that the setting of animation
544      * values will happen on the UI thread and that all animations will share
545      * the same times for calculating their values, which makes synchronizing
546      * animations possible.
547      *
548      * The handler uses the Choreographer for executing periodic callbacks.
549      *
550      * @hide
551      */
552     @SuppressWarnings("unchecked")
553     protected static class AnimationHandler implements Runnable {
554         // The per-thread list of all active animations
555         /** @hide */
556         protected final ArrayList<ValueAnimator> mAnimations = new ArrayList<ValueAnimator>();
557 
558         // Used in doAnimationFrame() to avoid concurrent modifications of mAnimations
559         private final ArrayList<ValueAnimator> mTmpAnimations = new ArrayList<ValueAnimator>();
560 
561         // The per-thread set of animations to be started on the next animation frame
562         /** @hide */
563         protected final ArrayList<ValueAnimator> mPendingAnimations = new ArrayList<ValueAnimator>();
564 
565         /**
566          * Internal per-thread collections used to avoid set collisions as animations start and end
567          * while being processed.
568          * @hide
569          */
570         protected final ArrayList<ValueAnimator> mDelayedAnims = new ArrayList<ValueAnimator>();
571         private final ArrayList<ValueAnimator> mEndingAnims = new ArrayList<ValueAnimator>();
572         private final ArrayList<ValueAnimator> mReadyAnims = new ArrayList<ValueAnimator>();
573 
574         private final Choreographer mChoreographer;
575         private boolean mAnimationScheduled;
576 
AnimationHandler()577         private AnimationHandler() {
578             mChoreographer = Choreographer.getInstance();
579         }
580 
581         /**
582          * Start animating on the next frame.
583          */
start()584         public void start() {
585             scheduleAnimation();
586         }
587 
doAnimationFrame(long frameTime)588         private void doAnimationFrame(long frameTime) {
589             // mPendingAnimations holds any animations that have requested to be started
590             // We're going to clear mPendingAnimations, but starting animation may
591             // cause more to be added to the pending list (for example, if one animation
592             // starting triggers another starting). So we loop until mPendingAnimations
593             // is empty.
594             while (mPendingAnimations.size() > 0) {
595                 ArrayList<ValueAnimator> pendingCopy =
596                         (ArrayList<ValueAnimator>) mPendingAnimations.clone();
597                 mPendingAnimations.clear();
598                 int count = pendingCopy.size();
599                 for (int i = 0; i < count; ++i) {
600                     ValueAnimator anim = pendingCopy.get(i);
601                     // If the animation has a startDelay, place it on the delayed list
602                     if (anim.mStartDelay == 0) {
603                         anim.startAnimation(this);
604                     } else {
605                         mDelayedAnims.add(anim);
606                     }
607                 }
608             }
609             // Next, process animations currently sitting on the delayed queue, adding
610             // them to the active animations if they are ready
611             int numDelayedAnims = mDelayedAnims.size();
612             for (int i = 0; i < numDelayedAnims; ++i) {
613                 ValueAnimator anim = mDelayedAnims.get(i);
614                 if (anim.delayedAnimationFrame(frameTime)) {
615                     mReadyAnims.add(anim);
616                 }
617             }
618             int numReadyAnims = mReadyAnims.size();
619             if (numReadyAnims > 0) {
620                 for (int i = 0; i < numReadyAnims; ++i) {
621                     ValueAnimator anim = mReadyAnims.get(i);
622                     anim.startAnimation(this);
623                     anim.mRunning = true;
624                     mDelayedAnims.remove(anim);
625                 }
626                 mReadyAnims.clear();
627             }
628 
629             // Now process all active animations. The return value from animationFrame()
630             // tells the handler whether it should now be ended
631             int numAnims = mAnimations.size();
632             for (int i = 0; i < numAnims; ++i) {
633                 mTmpAnimations.add(mAnimations.get(i));
634             }
635             for (int i = 0; i < numAnims; ++i) {
636                 ValueAnimator anim = mTmpAnimations.get(i);
637                 if (mAnimations.contains(anim) && anim.doAnimationFrame(frameTime)) {
638                     mEndingAnims.add(anim);
639                 }
640             }
641             mTmpAnimations.clear();
642             if (mEndingAnims.size() > 0) {
643                 for (int i = 0; i < mEndingAnims.size(); ++i) {
644                     mEndingAnims.get(i).endAnimation(this);
645                 }
646                 mEndingAnims.clear();
647             }
648 
649             // If there are still active or delayed animations, schedule a future call to
650             // onAnimate to process the next frame of the animations.
651             if (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty()) {
652                 scheduleAnimation();
653             }
654         }
655 
656         // Called by the Choreographer.
657         @Override
run()658         public void run() {
659             mAnimationScheduled = false;
660             doAnimationFrame(mChoreographer.getFrameTime());
661         }
662 
scheduleAnimation()663         private void scheduleAnimation() {
664             if (!mAnimationScheduled) {
665                 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
666                 mAnimationScheduled = true;
667             }
668         }
669     }
670 
671     /**
672      * The amount of time, in milliseconds, to delay starting the animation after
673      * {@link #start()} is called.
674      *
675      * @return the number of milliseconds to delay running the animation
676      */
getStartDelay()677     public long getStartDelay() {
678         return mUnscaledStartDelay;
679     }
680 
681     /**
682      * The amount of time, in milliseconds, to delay starting the animation after
683      * {@link #start()} is called.
684 
685      * @param startDelay The amount of the delay, in milliseconds
686      */
setStartDelay(long startDelay)687     public void setStartDelay(long startDelay) {
688         this.mStartDelay = (long)(startDelay * sDurationScale);
689         mUnscaledStartDelay = startDelay;
690     }
691 
692     /**
693      * The amount of time, in milliseconds, between each frame of the animation. This is a
694      * requested time that the animation will attempt to honor, but the actual delay between
695      * frames may be different, depending on system load and capabilities. This is a static
696      * function because the same delay will be applied to all animations, since they are all
697      * run off of a single timing loop.
698      *
699      * The frame delay may be ignored when the animation system uses an external timing
700      * source, such as the display refresh rate (vsync), to govern animations.
701      *
702      * @return the requested time between frames, in milliseconds
703      */
getFrameDelay()704     public static long getFrameDelay() {
705         return Choreographer.getFrameDelay();
706     }
707 
708     /**
709      * The amount of time, in milliseconds, between each frame of the animation. This is a
710      * requested time that the animation will attempt to honor, but the actual delay between
711      * frames may be different, depending on system load and capabilities. This is a static
712      * function because the same delay will be applied to all animations, since they are all
713      * run off of a single timing loop.
714      *
715      * The frame delay may be ignored when the animation system uses an external timing
716      * source, such as the display refresh rate (vsync), to govern animations.
717      *
718      * @param frameDelay the requested time between frames, in milliseconds
719      */
setFrameDelay(long frameDelay)720     public static void setFrameDelay(long frameDelay) {
721         Choreographer.setFrameDelay(frameDelay);
722     }
723 
724     /**
725      * The most recent value calculated by this <code>ValueAnimator</code> when there is just one
726      * property being animated. This value is only sensible while the animation is running. The main
727      * purpose for this read-only property is to retrieve the value from the <code>ValueAnimator</code>
728      * during a call to {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)}, which
729      * is called during each animation frame, immediately after the value is calculated.
730      *
731      * @return animatedValue The value most recently calculated by this <code>ValueAnimator</code> for
732      * the single property being animated. If there are several properties being animated
733      * (specified by several PropertyValuesHolder objects in the constructor), this function
734      * returns the animated value for the first of those objects.
735      */
getAnimatedValue()736     public Object getAnimatedValue() {
737         if (mValues != null && mValues.length > 0) {
738             return mValues[0].getAnimatedValue();
739         }
740         // Shouldn't get here; should always have values unless ValueAnimator was set up wrong
741         return null;
742     }
743 
744     /**
745      * The most recent value calculated by this <code>ValueAnimator</code> for <code>propertyName</code>.
746      * The main purpose for this read-only property is to retrieve the value from the
747      * <code>ValueAnimator</code> during a call to
748      * {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)}, which
749      * is called during each animation frame, immediately after the value is calculated.
750      *
751      * @return animatedValue The value most recently calculated for the named property
752      * by this <code>ValueAnimator</code>.
753      */
getAnimatedValue(String propertyName)754     public Object getAnimatedValue(String propertyName) {
755         PropertyValuesHolder valuesHolder = mValuesMap.get(propertyName);
756         if (valuesHolder != null) {
757             return valuesHolder.getAnimatedValue();
758         } else {
759             // At least avoid crashing if called with bogus propertyName
760             return null;
761         }
762     }
763 
764     /**
765      * Sets how many times the animation should be repeated. If the repeat
766      * count is 0, the animation is never repeated. If the repeat count is
767      * greater than 0 or {@link #INFINITE}, the repeat mode will be taken
768      * into account. The repeat count is 0 by default.
769      *
770      * @param value the number of times the animation should be repeated
771      */
setRepeatCount(int value)772     public void setRepeatCount(int value) {
773         mRepeatCount = value;
774     }
775     /**
776      * Defines how many times the animation should repeat. The default value
777      * is 0.
778      *
779      * @return the number of times the animation should repeat, or {@link #INFINITE}
780      */
getRepeatCount()781     public int getRepeatCount() {
782         return mRepeatCount;
783     }
784 
785     /**
786      * Defines what this animation should do when it reaches the end. This
787      * setting is applied only when the repeat count is either greater than
788      * 0 or {@link #INFINITE}. Defaults to {@link #RESTART}.
789      *
790      * @param value {@link #RESTART} or {@link #REVERSE}
791      */
setRepeatMode(int value)792     public void setRepeatMode(int value) {
793         mRepeatMode = value;
794     }
795 
796     /**
797      * Defines what this animation should do when it reaches the end.
798      *
799      * @return either one of {@link #REVERSE} or {@link #RESTART}
800      */
getRepeatMode()801     public int getRepeatMode() {
802         return mRepeatMode;
803     }
804 
805     /**
806      * Adds a listener to the set of listeners that are sent update events through the life of
807      * an animation. This method is called on all listeners for every frame of the animation,
808      * after the values for the animation have been calculated.
809      *
810      * @param listener the listener to be added to the current set of listeners for this animation.
811      */
addUpdateListener(AnimatorUpdateListener listener)812     public void addUpdateListener(AnimatorUpdateListener listener) {
813         if (mUpdateListeners == null) {
814             mUpdateListeners = new ArrayList<AnimatorUpdateListener>();
815         }
816         mUpdateListeners.add(listener);
817     }
818 
819     /**
820      * Removes all listeners from the set listening to frame updates for this animation.
821      */
removeAllUpdateListeners()822     public void removeAllUpdateListeners() {
823         if (mUpdateListeners == null) {
824             return;
825         }
826         mUpdateListeners.clear();
827         mUpdateListeners = null;
828     }
829 
830     /**
831      * Removes a listener from the set listening to frame updates for this animation.
832      *
833      * @param listener the listener to be removed from the current set of update listeners
834      * for this animation.
835      */
removeUpdateListener(AnimatorUpdateListener listener)836     public void removeUpdateListener(AnimatorUpdateListener listener) {
837         if (mUpdateListeners == null) {
838             return;
839         }
840         mUpdateListeners.remove(listener);
841         if (mUpdateListeners.size() == 0) {
842             mUpdateListeners = null;
843         }
844     }
845 
846 
847     /**
848      * The time interpolator used in calculating the elapsed fraction of this animation. The
849      * interpolator determines whether the animation runs with linear or non-linear motion,
850      * such as acceleration and deceleration. The default value is
851      * {@link android.view.animation.AccelerateDecelerateInterpolator}
852      *
853      * @param value the interpolator to be used by this animation. A value of <code>null</code>
854      * will result in linear interpolation.
855      */
856     @Override
setInterpolator(TimeInterpolator value)857     public void setInterpolator(TimeInterpolator value) {
858         if (value != null) {
859             mInterpolator = value;
860         } else {
861             mInterpolator = new LinearInterpolator();
862         }
863     }
864 
865     /**
866      * Returns the timing interpolator that this ValueAnimator uses.
867      *
868      * @return The timing interpolator for this ValueAnimator.
869      */
870     @Override
getInterpolator()871     public TimeInterpolator getInterpolator() {
872         return mInterpolator;
873     }
874 
875     /**
876      * The type evaluator to be used when calculating the animated values of this animation.
877      * The system will automatically assign a float or int evaluator based on the type
878      * of <code>startValue</code> and <code>endValue</code> in the constructor. But if these values
879      * are not one of these primitive types, or if different evaluation is desired (such as is
880      * necessary with int values that represent colors), a custom evaluator needs to be assigned.
881      * For example, when running an animation on color values, the {@link ArgbEvaluator}
882      * should be used to get correct RGB color interpolation.
883      *
884      * <p>If this ValueAnimator has only one set of values being animated between, this evaluator
885      * will be used for that set. If there are several sets of values being animated, which is
886      * the case if PropertyValuesHolder objects were set on the ValueAnimator, then the evaluator
887      * is assigned just to the first PropertyValuesHolder object.</p>
888      *
889      * @param value the evaluator to be used this animation
890      */
setEvaluator(TypeEvaluator value)891     public void setEvaluator(TypeEvaluator value) {
892         if (value != null && mValues != null && mValues.length > 0) {
893             mValues[0].setEvaluator(value);
894         }
895     }
896 
notifyStartListeners()897     private void notifyStartListeners() {
898         if (mListeners != null && !mStartListenersCalled) {
899             ArrayList<AnimatorListener> tmpListeners =
900                     (ArrayList<AnimatorListener>) mListeners.clone();
901             int numListeners = tmpListeners.size();
902             for (int i = 0; i < numListeners; ++i) {
903                 tmpListeners.get(i).onAnimationStart(this);
904             }
905         }
906         mStartListenersCalled = true;
907     }
908 
909     /**
910      * Start the animation playing. This version of start() takes a boolean flag that indicates
911      * whether the animation should play in reverse. The flag is usually false, but may be set
912      * to true if called from the reverse() method.
913      *
914      * <p>The animation started by calling this method will be run on the thread that called
915      * this method. This thread should have a Looper on it (a runtime exception will be thrown if
916      * this is not the case). Also, if the animation will animate
917      * properties of objects in the view hierarchy, then the calling thread should be the UI
918      * thread for that view hierarchy.</p>
919      *
920      * @param playBackwards Whether the ValueAnimator should start playing in reverse.
921      */
start(boolean playBackwards)922     private void start(boolean playBackwards) {
923         if (Looper.myLooper() == null) {
924             throw new AndroidRuntimeException("Animators may only be run on Looper threads");
925         }
926         mPlayingBackwards = playBackwards;
927         mCurrentIteration = 0;
928         mPlayingState = STOPPED;
929         mStarted = true;
930         mStartedDelay = false;
931         mPaused = false;
932         AnimationHandler animationHandler = getOrCreateAnimationHandler();
933         animationHandler.mPendingAnimations.add(this);
934         if (mStartDelay == 0) {
935             // This sets the initial value of the animation, prior to actually starting it running
936             setCurrentPlayTime(0);
937             mPlayingState = STOPPED;
938             mRunning = true;
939             notifyStartListeners();
940         }
941         animationHandler.start();
942     }
943 
944     @Override
start()945     public void start() {
946         start(false);
947     }
948 
949     @Override
cancel()950     public void cancel() {
951         // Only cancel if the animation is actually running or has been started and is about
952         // to run
953         AnimationHandler handler = getOrCreateAnimationHandler();
954         if (mPlayingState != STOPPED
955                 || handler.mPendingAnimations.contains(this)
956                 || handler.mDelayedAnims.contains(this)) {
957             // Only notify listeners if the animator has actually started
958             if ((mStarted || mRunning) && mListeners != null) {
959                 if (!mRunning) {
960                     // If it's not yet running, then start listeners weren't called. Call them now.
961                     notifyStartListeners();
962                 }
963                 ArrayList<AnimatorListener> tmpListeners =
964                         (ArrayList<AnimatorListener>) mListeners.clone();
965                 for (AnimatorListener listener : tmpListeners) {
966                     listener.onAnimationCancel(this);
967                 }
968             }
969             endAnimation(handler);
970         }
971     }
972 
973     @Override
end()974     public void end() {
975         AnimationHandler handler = getOrCreateAnimationHandler();
976         if (!handler.mAnimations.contains(this) && !handler.mPendingAnimations.contains(this)) {
977             // Special case if the animation has not yet started; get it ready for ending
978             mStartedDelay = false;
979             startAnimation(handler);
980             mStarted = true;
981         } else if (!mInitialized) {
982             initAnimation();
983         }
984         animateValue(mPlayingBackwards ? 0f : 1f);
985         endAnimation(handler);
986     }
987 
988     @Override
resume()989     public void resume() {
990         if (mPaused) {
991             mResumed = true;
992         }
993         super.resume();
994     }
995 
996     @Override
pause()997     public void pause() {
998         boolean previouslyPaused = mPaused;
999         super.pause();
1000         if (!previouslyPaused && mPaused) {
1001             mPauseTime = -1;
1002             mResumed = false;
1003         }
1004     }
1005 
1006     @Override
isRunning()1007     public boolean isRunning() {
1008         return (mPlayingState == RUNNING || mRunning);
1009     }
1010 
1011     @Override
isStarted()1012     public boolean isStarted() {
1013         return mStarted;
1014     }
1015 
1016     /**
1017      * Plays the ValueAnimator in reverse. If the animation is already running,
1018      * it will stop itself and play backwards from the point reached when reverse was called.
1019      * If the animation is not currently running, then it will start from the end and
1020      * play backwards. This behavior is only set for the current animation; future playing
1021      * of the animation will use the default behavior of playing forward.
1022      */
reverse()1023     public void reverse() {
1024         mPlayingBackwards = !mPlayingBackwards;
1025         if (mPlayingState == RUNNING) {
1026             long currentTime = AnimationUtils.currentAnimationTimeMillis();
1027             long currentPlayTime = currentTime - mStartTime;
1028             long timeLeft = mDuration - currentPlayTime;
1029             mStartTime = currentTime - timeLeft;
1030         } else if (mStarted) {
1031             end();
1032         } else {
1033             start(true);
1034         }
1035     }
1036 
1037     /**
1038      * Called internally to end an animation by removing it from the animations list. Must be
1039      * called on the UI thread.
1040      */
endAnimation(AnimationHandler handler)1041     private void endAnimation(AnimationHandler handler) {
1042         handler.mAnimations.remove(this);
1043         handler.mPendingAnimations.remove(this);
1044         handler.mDelayedAnims.remove(this);
1045         mPlayingState = STOPPED;
1046         mPaused = false;
1047         if ((mStarted || mRunning) && mListeners != null) {
1048             if (!mRunning) {
1049                 // If it's not yet running, then start listeners weren't called. Call them now.
1050                 notifyStartListeners();
1051              }
1052             ArrayList<AnimatorListener> tmpListeners =
1053                     (ArrayList<AnimatorListener>) mListeners.clone();
1054             int numListeners = tmpListeners.size();
1055             for (int i = 0; i < numListeners; ++i) {
1056                 tmpListeners.get(i).onAnimationEnd(this);
1057             }
1058         }
1059         mRunning = false;
1060         mStarted = false;
1061         mStartListenersCalled = false;
1062         mPlayingBackwards = false;
1063         if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
1064             Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, getNameForTrace(),
1065                     System.identityHashCode(this));
1066         }
1067     }
1068 
1069     /**
1070      * Called internally to start an animation by adding it to the active animations list. Must be
1071      * called on the UI thread.
1072      */
startAnimation(AnimationHandler handler)1073     private void startAnimation(AnimationHandler handler) {
1074         if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
1075             Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, getNameForTrace(),
1076                     System.identityHashCode(this));
1077         }
1078         initAnimation();
1079         handler.mAnimations.add(this);
1080         if (mStartDelay > 0 && mListeners != null) {
1081             // Listeners were already notified in start() if startDelay is 0; this is
1082             // just for delayed animations
1083             notifyStartListeners();
1084         }
1085     }
1086 
1087     /**
1088      * Returns the name of this animator for debugging purposes.
1089      */
getNameForTrace()1090     String getNameForTrace() {
1091         return "animator";
1092     }
1093 
1094 
1095     /**
1096      * Internal function called to process an animation frame on an animation that is currently
1097      * sleeping through its <code>startDelay</code> phase. The return value indicates whether it
1098      * should be woken up and put on the active animations queue.
1099      *
1100      * @param currentTime The current animation time, used to calculate whether the animation
1101      * has exceeded its <code>startDelay</code> and should be started.
1102      * @return True if the animation's <code>startDelay</code> has been exceeded and the animation
1103      * should be added to the set of active animations.
1104      */
delayedAnimationFrame(long currentTime)1105     private boolean delayedAnimationFrame(long currentTime) {
1106         if (!mStartedDelay) {
1107             mStartedDelay = true;
1108             mDelayStartTime = currentTime;
1109         } else {
1110             if (mPaused) {
1111                 if (mPauseTime < 0) {
1112                     mPauseTime = currentTime;
1113                 }
1114                 return false;
1115             } else if (mResumed) {
1116                 mResumed = false;
1117                 if (mPauseTime > 0) {
1118                     // Offset by the duration that the animation was paused
1119                     mDelayStartTime += (currentTime - mPauseTime);
1120                 }
1121             }
1122             long deltaTime = currentTime - mDelayStartTime;
1123             if (deltaTime > mStartDelay) {
1124                 // startDelay ended - start the anim and record the
1125                 // mStartTime appropriately
1126                 mStartTime = currentTime - (deltaTime - mStartDelay);
1127                 mPlayingState = RUNNING;
1128                 return true;
1129             }
1130         }
1131         return false;
1132     }
1133 
1134     /**
1135      * This internal function processes a single animation frame for a given animation. The
1136      * currentTime parameter is the timing pulse sent by the handler, used to calculate the
1137      * elapsed duration, and therefore
1138      * the elapsed fraction, of the animation. The return value indicates whether the animation
1139      * should be ended (which happens when the elapsed time of the animation exceeds the
1140      * animation's duration, including the repeatCount).
1141      *
1142      * @param currentTime The current time, as tracked by the static timing handler
1143      * @return true if the animation's duration, including any repetitions due to
1144      * <code>repeatCount</code>, has been exceeded and the animation should be ended.
1145      */
animationFrame(long currentTime)1146     boolean animationFrame(long currentTime) {
1147         boolean done = false;
1148         switch (mPlayingState) {
1149         case RUNNING:
1150         case SEEKED:
1151             float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f;
1152             if (fraction >= 1f) {
1153                 if (mCurrentIteration < mRepeatCount || mRepeatCount == INFINITE) {
1154                     // Time to repeat
1155                     if (mListeners != null) {
1156                         int numListeners = mListeners.size();
1157                         for (int i = 0; i < numListeners; ++i) {
1158                             mListeners.get(i).onAnimationRepeat(this);
1159                         }
1160                     }
1161                     if (mRepeatMode == REVERSE) {
1162                         mPlayingBackwards = !mPlayingBackwards;
1163                     }
1164                     mCurrentIteration += (int)fraction;
1165                     fraction = fraction % 1f;
1166                     mStartTime += mDuration;
1167                 } else {
1168                     done = true;
1169                     fraction = Math.min(fraction, 1.0f);
1170                 }
1171             }
1172             if (mPlayingBackwards) {
1173                 fraction = 1f - fraction;
1174             }
1175             animateValue(fraction);
1176             break;
1177         }
1178 
1179         return done;
1180     }
1181 
1182     /**
1183      * Processes a frame of the animation, adjusting the start time if needed.
1184      *
1185      * @param frameTime The frame time.
1186      * @return true if the animation has ended.
1187      */
doAnimationFrame(long frameTime)1188     final boolean doAnimationFrame(long frameTime) {
1189         if (mPlayingState == STOPPED) {
1190             mPlayingState = RUNNING;
1191             if (mSeekTime < 0) {
1192                 mStartTime = frameTime;
1193             } else {
1194                 mStartTime = frameTime - mSeekTime;
1195                 // Now that we're playing, reset the seek time
1196                 mSeekTime = -1;
1197             }
1198         }
1199         if (mPaused) {
1200             if (mPauseTime < 0) {
1201                 mPauseTime = frameTime;
1202             }
1203             return false;
1204         } else if (mResumed) {
1205             mResumed = false;
1206             if (mPauseTime > 0) {
1207                 // Offset by the duration that the animation was paused
1208                 mStartTime += (frameTime - mPauseTime);
1209             }
1210         }
1211         // The frame time might be before the start time during the first frame of
1212         // an animation.  The "current time" must always be on or after the start
1213         // time to avoid animating frames at negative time intervals.  In practice, this
1214         // is very rare and only happens when seeking backwards.
1215         final long currentTime = Math.max(frameTime, mStartTime);
1216         return animationFrame(currentTime);
1217     }
1218 
1219     /**
1220      * Returns the current animation fraction, which is the elapsed/interpolated fraction used in
1221      * the most recent frame update on the animation.
1222      *
1223      * @return Elapsed/interpolated fraction of the animation.
1224      */
getAnimatedFraction()1225     public float getAnimatedFraction() {
1226         return mCurrentFraction;
1227     }
1228 
1229     /**
1230      * This method is called with the elapsed fraction of the animation during every
1231      * animation frame. This function turns the elapsed fraction into an interpolated fraction
1232      * and then into an animated value (from the evaluator. The function is called mostly during
1233      * animation updates, but it is also called when the <code>end()</code>
1234      * function is called, to set the final value on the property.
1235      *
1236      * <p>Overrides of this method must call the superclass to perform the calculation
1237      * of the animated value.</p>
1238      *
1239      * @param fraction The elapsed fraction of the animation.
1240      */
animateValue(float fraction)1241     void animateValue(float fraction) {
1242         fraction = mInterpolator.getInterpolation(fraction);
1243         mCurrentFraction = fraction;
1244         int numValues = mValues.length;
1245         for (int i = 0; i < numValues; ++i) {
1246             mValues[i].calculateValue(fraction);
1247         }
1248         if (mUpdateListeners != null) {
1249             int numListeners = mUpdateListeners.size();
1250             for (int i = 0; i < numListeners; ++i) {
1251                 mUpdateListeners.get(i).onAnimationUpdate(this);
1252             }
1253         }
1254     }
1255 
1256     @Override
clone()1257     public ValueAnimator clone() {
1258         final ValueAnimator anim = (ValueAnimator) super.clone();
1259         if (mUpdateListeners != null) {
1260             ArrayList<AnimatorUpdateListener> oldListeners = mUpdateListeners;
1261             anim.mUpdateListeners = new ArrayList<AnimatorUpdateListener>();
1262             int numListeners = oldListeners.size();
1263             for (int i = 0; i < numListeners; ++i) {
1264                 anim.mUpdateListeners.add(oldListeners.get(i));
1265             }
1266         }
1267         anim.mSeekTime = -1;
1268         anim.mPlayingBackwards = false;
1269         anim.mCurrentIteration = 0;
1270         anim.mInitialized = false;
1271         anim.mPlayingState = STOPPED;
1272         anim.mStartedDelay = false;
1273         PropertyValuesHolder[] oldValues = mValues;
1274         if (oldValues != null) {
1275             int numValues = oldValues.length;
1276             anim.mValues = new PropertyValuesHolder[numValues];
1277             anim.mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
1278             for (int i = 0; i < numValues; ++i) {
1279                 PropertyValuesHolder newValuesHolder = oldValues[i].clone();
1280                 anim.mValues[i] = newValuesHolder;
1281                 anim.mValuesMap.put(newValuesHolder.getPropertyName(), newValuesHolder);
1282             }
1283         }
1284         return anim;
1285     }
1286 
1287     /**
1288      * Implementors of this interface can add themselves as update listeners
1289      * to an <code>ValueAnimator</code> instance to receive callbacks on every animation
1290      * frame, after the current frame's values have been calculated for that
1291      * <code>ValueAnimator</code>.
1292      */
1293     public static interface AnimatorUpdateListener {
1294         /**
1295          * <p>Notifies the occurrence of another frame of the animation.</p>
1296          *
1297          * @param animation The animation which was repeated.
1298          */
onAnimationUpdate(ValueAnimator animation)1299         void onAnimationUpdate(ValueAnimator animation);
1300 
1301     }
1302 
1303     /**
1304      * Return the number of animations currently running.
1305      *
1306      * Used by StrictMode internally to annotate violations.
1307      * May be called on arbitrary threads!
1308      *
1309      * @hide
1310      */
getCurrentAnimationsCount()1311     public static int getCurrentAnimationsCount() {
1312         AnimationHandler handler = sAnimationHandler.get();
1313         return handler != null ? handler.mAnimations.size() : 0;
1314     }
1315 
1316     /**
1317      * Clear all animations on this thread, without canceling or ending them.
1318      * This should be used with caution.
1319      *
1320      * @hide
1321      */
clearAllAnimations()1322     public static void clearAllAnimations() {
1323         AnimationHandler handler = sAnimationHandler.get();
1324         if (handler != null) {
1325             handler.mAnimations.clear();
1326             handler.mPendingAnimations.clear();
1327             handler.mDelayedAnims.clear();
1328         }
1329     }
1330 
getOrCreateAnimationHandler()1331     private static AnimationHandler getOrCreateAnimationHandler() {
1332         AnimationHandler handler = sAnimationHandler.get();
1333         if (handler == null) {
1334             handler = new AnimationHandler();
1335             sAnimationHandler.set(handler);
1336         }
1337         return handler;
1338     }
1339 
1340     @Override
toString()1341     public String toString() {
1342         String returnVal = "ValueAnimator@" + Integer.toHexString(hashCode());
1343         if (mValues != null) {
1344             for (int i = 0; i < mValues.length; ++i) {
1345                 returnVal += "\n    " + mValues[i].toString();
1346             }
1347         }
1348         return returnVal;
1349     }
1350 }
1351