ObjectAnimator.java revision 4eed52944c0fcb3afa7369aba60fb5c655580286
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
17package android.animation;
18
19import android.util.Log;
20import android.util.Property;
21
22import java.util.ArrayList;
23
24/**
25 * This subclass of {@link ValueAnimator} provides support for animating properties on target objects.
26 * The constructors of this class take parameters to define the target object that will be animated
27 * as well as the name of the property that will be animated. Appropriate set/get functions
28 * are then determined internally and the animation will call these functions as necessary to
29 * animate the property.
30 *
31 * <div class="special reference">
32 * <h3>Developer Guides</h3>
33 * <p>For more information about animating with {@code ObjectAnimator}, read the
34 * <a href="{@docRoot}guide/topics/graphics/prop-animation.html#object-animator">Property
35 * Animation</a> developer guide.</p>
36 * </div>
37 *
38 * @see #setPropertyName(String)
39 *
40 */
41public final class ObjectAnimator extends ValueAnimator {
42    private static final boolean DBG = false;
43
44    // The target object on which the property exists, set in the constructor
45    private Object mTarget;
46
47    private String mPropertyName;
48
49    private Property mProperty;
50
51    private boolean mAutoCancel = false;
52
53    /**
54     * Sets the name of the property that will be animated. This name is used to derive
55     * a setter function that will be called to set animated values.
56     * For example, a property name of <code>foo</code> will result
57     * in a call to the function <code>setFoo()</code> on the target object. If either
58     * <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will
59     * also be derived and called.
60     *
61     * <p>For best performance of the mechanism that calls the setter function determined by the
62     * name of the property being animated, use <code>float</code> or <code>int</code> typed values,
63     * and make the setter function for those properties have a <code>void</code> return value. This
64     * will cause the code to take an optimized path for these constrained circumstances. Other
65     * property types and return types will work, but will have more overhead in processing
66     * the requests due to normal reflection mechanisms.</p>
67     *
68     * <p>Note that the setter function derived from this property name
69     * must take the same parameter type as the
70     * <code>valueFrom</code> and <code>valueTo</code> properties, otherwise the call to
71     * the setter function will fail.</p>
72     *
73     * <p>If this ObjectAnimator has been set up to animate several properties together,
74     * using more than one PropertyValuesHolder objects, then setting the propertyName simply
75     * sets the propertyName in the first of those PropertyValuesHolder objects.</p>
76     *
77     * @param propertyName The name of the property being animated. Should not be null.
78     */
79    public void setPropertyName(String propertyName) {
80        // mValues could be null if this is being constructed piecemeal. Just record the
81        // propertyName to be used later when setValues() is called if so.
82        if (mValues != null) {
83            PropertyValuesHolder valuesHolder = mValues[0];
84            String oldName = valuesHolder.getPropertyName();
85            valuesHolder.setPropertyName(propertyName);
86            mValuesMap.remove(oldName);
87            mValuesMap.put(propertyName, valuesHolder);
88        }
89        mPropertyName = propertyName;
90        // New property/values/target should cause re-initialization prior to starting
91        mInitialized = false;
92    }
93
94    /**
95     * Sets the property that will be animated. Property objects will take precedence over
96     * properties specified by the {@link #setPropertyName(String)} method. Animations should
97     * be set up to use one or the other, not both.
98     *
99     * @param property The property being animated. Should not be null.
100     */
101    public void setProperty(Property property) {
102        // mValues could be null if this is being constructed piecemeal. Just record the
103        // propertyName to be used later when setValues() is called if so.
104        if (mValues != null) {
105            PropertyValuesHolder valuesHolder = mValues[0];
106            String oldName = valuesHolder.getPropertyName();
107            valuesHolder.setProperty(property);
108            mValuesMap.remove(oldName);
109            mValuesMap.put(mPropertyName, valuesHolder);
110        }
111        if (mProperty != null) {
112            mPropertyName = property.getName();
113        }
114        mProperty = property;
115        // New property/values/target should cause re-initialization prior to starting
116        mInitialized = false;
117    }
118
119    /**
120     * Gets the name of the property that will be animated. This name will be used to derive
121     * a setter function that will be called to set animated values.
122     * For example, a property name of <code>foo</code> will result
123     * in a call to the function <code>setFoo()</code> on the target object. If either
124     * <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will
125     * also be derived and called.
126     *
127     * <p>If this animator was created with a {@link Property} object instead of the
128     * string name of a property, then this method will return the {@link
129     * Property#getName() name} of that Property object instead. If this animator was
130     * created with one or more {@link PropertyValuesHolder} objects, then this method
131     * will return the {@link PropertyValuesHolder#getPropertyName() name} of that
132     * object (if there was just one) or a comma-separated list of all of the
133     * names (if there are more than one).</p>
134     */
135    public String getPropertyName() {
136        String propertyName = null;
137        if (mPropertyName != null) {
138            propertyName = mPropertyName;
139        } else if (mProperty != null) {
140            propertyName = mProperty.getName();
141        } else if (mValues != null && mValues.length > 0) {
142            for (int i = 0; i < mValues.length; ++i) {
143                if (i == 0) {
144                    propertyName = "";
145                } else {
146                    propertyName += ",";
147                }
148                propertyName += mValues[i].getPropertyName();
149            }
150        }
151        return propertyName;
152    }
153
154    @Override
155    String getNameForTrace() {
156        return "animator:" + getPropertyName();
157    }
158
159    /**
160     * Creates a new ObjectAnimator object. This default constructor is primarily for
161     * use internally; the other constructors which take parameters are more generally
162     * useful.
163     */
164    public ObjectAnimator() {
165    }
166
167    /**
168     * Private utility constructor that initializes the target object and name of the
169     * property being animated.
170     *
171     * @param target The object whose property is to be animated. This object should
172     * have a public method on it called <code>setName()</code>, where <code>name</code> is
173     * the value of the <code>propertyName</code> parameter.
174     * @param propertyName The name of the property being animated.
175     */
176    private ObjectAnimator(Object target, String propertyName) {
177        mTarget = target;
178        setPropertyName(propertyName);
179    }
180
181    /**
182     * Private utility constructor that initializes the target object and property being animated.
183     *
184     * @param target The object whose property is to be animated.
185     * @param property The property being animated.
186     */
187    private <T> ObjectAnimator(T target, Property<T, ?> property) {
188        mTarget = target;
189        setProperty(property);
190    }
191
192    /**
193     * Constructs and returns an ObjectAnimator that animates between int values. A single
194     * value implies that that value is the one being animated to. Two values imply starting
195     * and ending values. More than two values imply a starting value, values to animate through
196     * along the way, and an ending value (these values will be distributed evenly across
197     * the duration of the animation).
198     *
199     * @param target The object whose property is to be animated. This object should
200     * have a public method on it called <code>setName()</code>, where <code>name</code> is
201     * the value of the <code>propertyName</code> parameter.
202     * @param propertyName The name of the property being animated.
203     * @param values A set of values that the animation will animate between over time.
204     * @return An ObjectAnimator object that is set up to animate between the given values.
205     */
206    public static ObjectAnimator ofInt(Object target, String propertyName, int... values) {
207        ObjectAnimator anim = new ObjectAnimator(target, propertyName);
208        anim.setIntValues(values);
209        return anim;
210    }
211
212    /**
213     * Constructs and returns an ObjectAnimator that animates between int values. A single
214     * value implies that that value is the one being animated to. Two values imply starting
215     * and ending values. More than two values imply a starting value, values to animate through
216     * along the way, and an ending value (these values will be distributed evenly across
217     * the duration of the animation).
218     *
219     * @param target The object whose property is to be animated.
220     * @param property The property being animated.
221     * @param values A set of values that the animation will animate between over time.
222     * @return An ObjectAnimator object that is set up to animate between the given values.
223     */
224    public static <T> ObjectAnimator ofInt(T target, Property<T, Integer> property, int... values) {
225        ObjectAnimator anim = new ObjectAnimator(target, property);
226        anim.setIntValues(values);
227        return anim;
228    }
229
230    /**
231     * Constructs and returns an ObjectAnimator that animates over int values for a multiple
232     * parameters setter. Only public methods that take only int parameters are supported.
233     * Each <code>int[]</code> contains a complete set of parameters to the setter method.
234     * At least two <code>int[]</code> values must be provided, a start and end. More than two
235     * values imply a starting value, values to animate through along the way, and an ending
236     * value (these values will be distributed evenly across the duration of the animation).
237     *
238     * @param target The object whose property is to be animated. This object may
239     * have a public method on it called <code>setName()</code>, where <code>name</code> is
240     * the value of the <code>propertyName</code> parameter. <code>propertyName</code> may also
241     * be the case-sensitive complete name of the public setter method.
242     * @param propertyName The name of the property being animated or the name of the setter method.
243     * @param values A set of values that the animation will animate between over time.
244     * @return An ObjectAnimator object that is set up to animate between the given values.
245     */
246    public static ObjectAnimator ofMultiInt(Object target, String propertyName, int[][] values) {
247        PropertyValuesHolder pvh = PropertyValuesHolder.ofMultiInt(propertyName, values);
248        return ofPropertyValuesHolder(target, pvh);
249    }
250
251    /**
252     * Constructs and returns an ObjectAnimator that animates over values for a multiple int
253     * parameters setter. Only public methods that take only int parameters are supported.
254     * <p>At least two values must be provided, a start and end. More than two
255     * values imply a starting value, values to animate through along the way, and an ending
256     * value (these values will be distributed evenly across the duration of the animation).</p>
257     *
258     * @param target The object whose property is to be animated. This object may
259     * have a public method on it called <code>setName()</code>, where <code>name</code> is
260     * the value of the <code>propertyName</code> parameter. <code>propertyName</code> may also
261     * be the complete name of the public method.
262     * @param propertyName The name of the property being animated or the name of the setter method.
263     * @param converter Converts T objects into int parameters for the multi-value setter.
264     * @param evaluator A TypeEvaluator that will be called on each animation frame to
265     * provide the necessary interpolation between the Object values to derive the animated
266     * value.
267     * @param values A set of values that the animation will animate between over time.
268     * @return An ObjectAnimator object that is set up to animate between the given values.
269     */
270    public static <T> ObjectAnimator ofMultiInt(Object target, String propertyName,
271            TypeConverter<T, int[]> converter, TypeEvaluator<T> evaluator, T... values) {
272        PropertyValuesHolder pvh = PropertyValuesHolder.ofMultiInt(propertyName, converter,
273                evaluator, values);
274        return ObjectAnimator.ofPropertyValuesHolder(target, pvh);
275    }
276
277    /**
278     * Constructs and returns an ObjectAnimator that animates between float values. A single
279     * value implies that that value is the one being animated to. Two values imply starting
280     * and ending values. More than two values imply a starting value, values to animate through
281     * along the way, and an ending value (these values will be distributed evenly across
282     * the duration of the animation).
283     *
284     * @param target The object whose property is to be animated. This object should
285     * have a public method on it called <code>setName()</code>, where <code>name</code> is
286     * the value of the <code>propertyName</code> parameter.
287     * @param propertyName The name of the property being animated.
288     * @param values A set of values that the animation will animate between over time.
289     * @return An ObjectAnimator object that is set up to animate between the given values.
290     */
291    public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
292        ObjectAnimator anim = new ObjectAnimator(target, propertyName);
293        anim.setFloatValues(values);
294        return anim;
295    }
296
297    /**
298     * Constructs and returns an ObjectAnimator that animates between float values. A single
299     * value implies that that value is the one being animated to. Two values imply starting
300     * and ending values. More than two values imply a starting value, values to animate through
301     * along the way, and an ending value (these values will be distributed evenly across
302     * the duration of the animation).
303     *
304     * @param target The object whose property is to be animated.
305     * @param property The property being animated.
306     * @param values A set of values that the animation will animate between over time.
307     * @return An ObjectAnimator object that is set up to animate between the given values.
308     */
309    public static <T> ObjectAnimator ofFloat(T target, Property<T, Float> property,
310            float... values) {
311        ObjectAnimator anim = new ObjectAnimator(target, property);
312        anim.setFloatValues(values);
313        return anim;
314    }
315
316    /**
317     * Constructs and returns an ObjectAnimator that animates over float values for a multiple
318     * parameters setter. Only public methods that take only float parameters are supported.
319     * Each <code>float[]</code> contains a complete set of parameters to the setter method.
320     * At least two <code>float[]</code> values must be provided, a start and end. More than two
321     * values imply a starting value, values to animate through along the way, and an ending
322     * value (these values will be distributed evenly across the duration of the animation).
323     *
324     * @param target The object whose property is to be animated. This object may
325     * have a public method on it called <code>setName()</code>, where <code>name</code> is
326     * the value of the <code>propertyName</code> parameter. <code>propertyName</code> may also
327     * be the complete name of the public method.
328     * @param propertyName The name of the property being animated or the name of the setter method.
329     * @param values A set of values that the animation will animate between over time.
330     * @return An ObjectAnimator object that is set up to animate between the given values.
331     */
332    public static ObjectAnimator ofMultiFloat(Object target, String propertyName,
333            float[][] values) {
334        PropertyValuesHolder pvh = PropertyValuesHolder.ofMultiFloat(propertyName, values);
335        return ofPropertyValuesHolder(target, pvh);
336    }
337
338    /**
339     * Constructs and returns an ObjectAnimator that animates over values for a multiple float
340     * parameters setter. Only public methods that take only float parameters are supported.
341     * <p>At least two values must be provided, a start and end. More than two
342     * values imply a starting value, values to animate through along the way, and an ending
343     * value (these values will be distributed evenly across the duration of the animation).</p>
344     *
345     * @param target The object whose property is to be animated. This object may
346     * have a public method on it called <code>setName()</code>, where <code>name</code> is
347     * the value of the <code>propertyName</code> parameter. <code>propertyName</code> may also
348     * be the case-sensitive complete name of the public setter method.
349     * @param propertyName The name of the property being animated or the name of the setter method.
350     * @param converter Converts T objects into float parameters for the multi-value setter.
351     * @param evaluator A TypeEvaluator that will be called on each animation frame to
352     * provide the necessary interpolation between the Object values to derive the animated
353     * value.
354     * @param values A set of values that the animation will animate between over time.
355     * @return An ObjectAnimator object that is set up to animate between the given values.
356     */
357    public static <T> ObjectAnimator ofMultiFloat(Object target, String propertyName,
358            TypeConverter<T, float[]> converter, TypeEvaluator<T> evaluator, T... values) {
359        PropertyValuesHolder pvh = PropertyValuesHolder.ofMultiFloat(propertyName, converter,
360                evaluator, values);
361        return ObjectAnimator.ofPropertyValuesHolder(target, pvh);
362    }
363
364    /**
365     * Constructs and returns an ObjectAnimator that animates between Object values. A single
366     * value implies that that value is the one being animated to. Two values imply starting
367     * and ending values. More than two values imply a starting value, values to animate through
368     * along the way, and an ending value (these values will be distributed evenly across
369     * the duration of the animation).
370     *
371     * @param target The object whose property is to be animated. This object should
372     * have a public method on it called <code>setName()</code>, where <code>name</code> is
373     * the value of the <code>propertyName</code> parameter.
374     * @param propertyName The name of the property being animated.
375     * @param evaluator A TypeEvaluator that will be called on each animation frame to
376     * provide the necessary interpolation between the Object values to derive the animated
377     * value.
378     * @param values A set of values that the animation will animate between over time.
379     * @return An ObjectAnimator object that is set up to animate between the given values.
380     */
381    public static ObjectAnimator ofObject(Object target, String propertyName,
382            TypeEvaluator evaluator, Object... values) {
383        ObjectAnimator anim = new ObjectAnimator(target, propertyName);
384        anim.setObjectValues(values);
385        anim.setEvaluator(evaluator);
386        return anim;
387    }
388
389    /**
390     * Constructs and returns an ObjectAnimator that animates between Object values. A single
391     * value implies that that value is the one being animated to. Two values imply starting
392     * and ending values. More than two values imply a starting value, values to animate through
393     * along the way, and an ending value (these values will be distributed evenly across
394     * the duration of the animation).
395     *
396     * @param target The object whose property is to be animated.
397     * @param property The property being animated.
398     * @param evaluator A TypeEvaluator that will be called on each animation frame to
399     * provide the necessary interpolation between the Object values to derive the animated
400     * value.
401     * @param values A set of values that the animation will animate between over time.
402     * @return An ObjectAnimator object that is set up to animate between the given values.
403     */
404    public static <T, V> ObjectAnimator ofObject(T target, Property<T, V> property,
405            TypeEvaluator<V> evaluator, V... values) {
406        ObjectAnimator anim = new ObjectAnimator(target, property);
407        anim.setObjectValues(values);
408        anim.setEvaluator(evaluator);
409        return anim;
410    }
411
412    /**
413     * Constructs and returns an ObjectAnimator that animates between Object values. A single
414     * value implies that that value is the one being animated to. Two values imply starting
415     * and ending values. More than two values imply a starting value, values to animate through
416     * along the way, and an ending value (these values will be distributed evenly across
417     * the duration of the animation). This variant supplies a <code>TypeConverter</code> to
418     * convert from the animated values to the type of the property. If only one value is
419     * supplied, the <code>TypeConverter</code> must implement
420     * {@link TypeConverter#convertBack(Object)} to retrieve the current value.
421     *
422     * @param target The object whose property is to be animated.
423     * @param property The property being animated.
424     * @param converter Converts the animated object to the Property type.
425     * @param evaluator A TypeEvaluator that will be called on each animation frame to
426     * provide the necessary interpolation between the Object values to derive the animated
427     * value.
428     * @param values A set of values that the animation will animate between over time.
429     * @return An ObjectAnimator object that is set up to animate between the given values.
430     */
431    public static <T, V, P> ObjectAnimator ofObject(T target, Property<T, P> property,
432            TypeConverter<V, P> converter, TypeEvaluator<V> evaluator, V... values) {
433        PropertyValuesHolder pvh = PropertyValuesHolder.ofObject(property, converter, evaluator,
434                values);
435        return ofPropertyValuesHolder(target, pvh);
436    }
437
438    /**
439     * Constructs and returns an ObjectAnimator that animates between the sets of values specified
440     * in <code>PropertyValueHolder</code> objects. This variant should be used when animating
441     * several properties at once with the same ObjectAnimator, since PropertyValuesHolder allows
442     * you to associate a set of animation values with a property name.
443     *
444     * @param target The object whose property is to be animated. Depending on how the
445     * PropertyValuesObjects were constructed, the target object should either have the {@link
446     * android.util.Property} objects used to construct the PropertyValuesHolder objects or (if the
447     * PropertyValuesHOlder objects were created with property names) the target object should have
448     * public methods on it called <code>setName()</code>, where <code>name</code> is the name of
449     * the property passed in as the <code>propertyName</code> parameter for each of the
450     * PropertyValuesHolder objects.
451     * @param values A set of PropertyValuesHolder objects whose values will be animated between
452     * over time.
453     * @return An ObjectAnimator object that is set up to animate between the given values.
454     */
455    public static ObjectAnimator ofPropertyValuesHolder(Object target,
456            PropertyValuesHolder... values) {
457        ObjectAnimator anim = new ObjectAnimator();
458        anim.mTarget = target;
459        anim.setValues(values);
460        return anim;
461    }
462
463    @Override
464    public void setIntValues(int... values) {
465        if (mValues == null || mValues.length == 0) {
466            // No values yet - this animator is being constructed piecemeal. Init the values with
467            // whatever the current propertyName is
468            if (mProperty != null) {
469                setValues(PropertyValuesHolder.ofInt(mProperty, values));
470            } else {
471                setValues(PropertyValuesHolder.ofInt(mPropertyName, values));
472            }
473        } else {
474            super.setIntValues(values);
475        }
476    }
477
478    @Override
479    public void setFloatValues(float... values) {
480        if (mValues == null || mValues.length == 0) {
481            // No values yet - this animator is being constructed piecemeal. Init the values with
482            // whatever the current propertyName is
483            if (mProperty != null) {
484                setValues(PropertyValuesHolder.ofFloat(mProperty, values));
485            } else {
486                setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));
487            }
488        } else {
489            super.setFloatValues(values);
490        }
491    }
492
493    @Override
494    public void setObjectValues(Object... values) {
495        if (mValues == null || mValues.length == 0) {
496            // No values yet - this animator is being constructed piecemeal. Init the values with
497            // whatever the current propertyName is
498            if (mProperty != null) {
499                setValues(PropertyValuesHolder.ofObject(mProperty, (TypeEvaluator) null, values));
500            } else {
501                setValues(PropertyValuesHolder.ofObject(mPropertyName,
502                        (TypeEvaluator) null, values));
503            }
504        } else {
505            super.setObjectValues(values);
506        }
507    }
508
509    /**
510     * autoCancel controls whether an ObjectAnimator will be canceled automatically
511     * when any other ObjectAnimator with the same target and properties is started.
512     * Setting this flag may make it easier to run different animators on the same target
513     * object without having to keep track of whether there are conflicting animators that
514     * need to be manually canceled. Canceling animators must have the same exact set of
515     * target properties, in the same order.
516     *
517     * @param cancel Whether future ObjectAnimators with the same target and properties
518     * as this ObjectAnimator will cause this ObjectAnimator to be canceled.
519     */
520    public void setAutoCancel(boolean cancel) {
521        mAutoCancel = cancel;
522    }
523
524    private boolean hasSameTargetAndProperties(Animator anim) {
525        if (anim instanceof ObjectAnimator) {
526            PropertyValuesHolder[] theirValues = ((ObjectAnimator) anim).getValues();
527            if (((ObjectAnimator) anim).getTarget() == mTarget &&
528                    mValues.length == theirValues.length) {
529                for (int i = 0; i < mValues.length; ++i) {
530                    PropertyValuesHolder pvhMine = mValues[i];
531                    PropertyValuesHolder pvhTheirs = theirValues[i];
532                    if (pvhMine.getPropertyName() == null ||
533                            !pvhMine.getPropertyName().equals(pvhTheirs.getPropertyName())) {
534                        return false;
535                    }
536                }
537                return true;
538            }
539        }
540        return false;
541    }
542
543    @Override
544    public void start() {
545        // See if any of the current active/pending animators need to be canceled
546        AnimationHandler handler = sAnimationHandler.get();
547        if (handler != null) {
548            int numAnims = handler.mAnimations.size();
549            for (int i = numAnims - 1; i >= 0; i--) {
550                if (handler.mAnimations.get(i) instanceof ObjectAnimator) {
551                    ObjectAnimator anim = (ObjectAnimator) handler.mAnimations.get(i);
552                    if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
553                        anim.cancel();
554                    }
555                }
556            }
557            numAnims = handler.mPendingAnimations.size();
558            for (int i = numAnims - 1; i >= 0; i--) {
559                if (handler.mPendingAnimations.get(i) instanceof ObjectAnimator) {
560                    ObjectAnimator anim = (ObjectAnimator) handler.mPendingAnimations.get(i);
561                    if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
562                        anim.cancel();
563                    }
564                }
565            }
566            numAnims = handler.mDelayedAnims.size();
567            for (int i = numAnims - 1; i >= 0; i--) {
568                if (handler.mDelayedAnims.get(i) instanceof ObjectAnimator) {
569                    ObjectAnimator anim = (ObjectAnimator) handler.mDelayedAnims.get(i);
570                    if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
571                        anim.cancel();
572                    }
573                }
574            }
575        }
576        if (DBG) {
577            Log.d("ObjectAnimator", "Anim target, duration: " + mTarget + ", " + getDuration());
578            for (int i = 0; i < mValues.length; ++i) {
579                PropertyValuesHolder pvh = mValues[i];
580                ArrayList<Keyframe> keyframes = pvh.mKeyframeSet.mKeyframes;
581                Log.d("ObjectAnimator", "   Values[" + i + "]: " +
582                    pvh.getPropertyName() + ", " + keyframes.get(0).getValue() + ", " +
583                    keyframes.get(pvh.mKeyframeSet.mNumKeyframes - 1).getValue());
584            }
585        }
586        super.start();
587    }
588
589    /**
590     * This function is called immediately before processing the first animation
591     * frame of an animation. If there is a nonzero <code>startDelay</code>, the
592     * function is called after that delay ends.
593     * It takes care of the final initialization steps for the
594     * animation. This includes setting mEvaluator, if the user has not yet
595     * set it up, and the setter/getter methods, if the user did not supply
596     * them.
597     *
598     *  <p>Overriders of this method should call the superclass method to cause
599     *  internal mechanisms to be set up correctly.</p>
600     */
601    @Override
602    void initAnimation() {
603        if (!mInitialized) {
604            // mValueType may change due to setter/getter setup; do this before calling super.init(),
605            // which uses mValueType to set up the default type evaluator.
606            int numValues = mValues.length;
607            for (int i = 0; i < numValues; ++i) {
608                mValues[i].setupSetterAndGetter(mTarget);
609            }
610            super.initAnimation();
611        }
612    }
613
614    /**
615     * Sets the length of the animation. The default duration is 300 milliseconds.
616     *
617     * @param duration The length of the animation, in milliseconds.
618     * @return ObjectAnimator The object called with setDuration(). This return
619     * value makes it easier to compose statements together that construct and then set the
620     * duration, as in
621     * <code>ObjectAnimator.ofInt(target, propertyName, 0, 10).setDuration(500).start()</code>.
622     */
623    @Override
624    public ObjectAnimator setDuration(long duration) {
625        super.setDuration(duration);
626        return this;
627    }
628
629
630    /**
631     * The target object whose property will be animated by this animation
632     *
633     * @return The object being animated
634     */
635    public Object getTarget() {
636        return mTarget;
637    }
638
639    /**
640     * Sets the target object whose property will be animated by this animation
641     *
642     * @param target The object being animated
643     */
644    @Override
645    public void setTarget(Object target) {
646        if (mTarget != target) {
647            final Object oldTarget = mTarget;
648            mTarget = target;
649            if (oldTarget != null && target != null && oldTarget.getClass() == target.getClass()) {
650                return;
651            }
652            // New target type should cause re-initialization prior to starting
653            mInitialized = false;
654        }
655    }
656
657    @Override
658    public void setupStartValues() {
659        initAnimation();
660        int numValues = mValues.length;
661        for (int i = 0; i < numValues; ++i) {
662            mValues[i].setupStartValue(mTarget);
663        }
664    }
665
666    @Override
667    public void setupEndValues() {
668        initAnimation();
669        int numValues = mValues.length;
670        for (int i = 0; i < numValues; ++i) {
671            mValues[i].setupEndValue(mTarget);
672        }
673    }
674
675    /**
676     * This method is called with the elapsed fraction of the animation during every
677     * animation frame. This function turns the elapsed fraction into an interpolated fraction
678     * and then into an animated value (from the evaluator. The function is called mostly during
679     * animation updates, but it is also called when the <code>end()</code>
680     * function is called, to set the final value on the property.
681     *
682     * <p>Overrides of this method must call the superclass to perform the calculation
683     * of the animated value.</p>
684     *
685     * @param fraction The elapsed fraction of the animation.
686     */
687    @Override
688    void animateValue(float fraction) {
689        super.animateValue(fraction);
690        int numValues = mValues.length;
691        for (int i = 0; i < numValues; ++i) {
692            mValues[i].setAnimatedValue(mTarget);
693        }
694    }
695
696    @Override
697    public ObjectAnimator clone() {
698        final ObjectAnimator anim = (ObjectAnimator) super.clone();
699        return anim;
700    }
701
702    @Override
703    public String toString() {
704        String returnVal = "ObjectAnimator@" + Integer.toHexString(hashCode()) + ", target " +
705            mTarget;
706        if (mValues != null) {
707            for (int i = 0; i < mValues.length; ++i) {
708                returnVal += "\n    " + mValues[i].toString();
709            }
710        }
711        return returnVal;
712    }
713}
714