PropertyValuesHolder.java revision 41f041d9986f8a5d45b6cb0b86e881c81a412168
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;
20
21import java.lang.reflect.InvocationTargetException;
22import java.lang.reflect.Method;
23import java.util.ArrayList;
24import java.util.HashMap;
25import java.util.concurrent.locks.ReentrantReadWriteLock;
26
27/**
28 * This class holds information about a property and the values that that property
29 * should take on during an animation. PropertyValuesHolder objects can be used to create
30 * animations with ValueAnimator or ObjectAnimator that operate on several different properties
31 * in parallel.
32 */
33public class PropertyValuesHolder implements Cloneable {
34
35    /**
36     * The name of the property associated with the values. This need not be a real property,
37     * unless this object is being used with ObjectAnimator. But this is the name by which
38     * aniamted values are looked up with getAnimatedValue(String) in ValueAnimator.
39     */
40    private String mPropertyName;
41
42    /**
43     * The setter function, if needed. ObjectAnimator hands off this functionality to
44     * PropertyValuesHolder, since it holds all of the per-property information. This
45     * property can be manually set via setSetter(). Otherwise, it is automatically
46     * derived when the animation starts in setupSetterAndGetter() if using ObjectAnimator.
47     */
48    private Method mSetter = null;
49
50    /**
51     * The getter function, if needed. ObjectAnimator hands off this functionality to
52     * PropertyValuesHolder, since it holds all of the per-property information. This
53     * property can be manually set via setSetter(). Otherwise, it is automatically
54     * derived when the animation starts in setupSetterAndGetter() if using ObjectAnimator.
55     * The getter is only derived and used if one of the values is null.
56     */
57    private Method mGetter = null;
58
59    /**
60     * The type of values supplied. This information is used both in deriving the setter/getter
61     * functions and in deriving the type of TypeEvaluator.
62     */
63    private Class mValueType;
64
65    /**
66     * The set of keyframes (time/value pairs) that define this animation.
67     */
68    private KeyframeSet mKeyframeSet = null;
69
70
71    // type evaluators for the three primitive types handled by this implementation
72    private static final TypeEvaluator sIntEvaluator = new IntEvaluator();
73    private static final TypeEvaluator sFloatEvaluator = new FloatEvaluator();
74    private static final TypeEvaluator sDoubleEvaluator = new DoubleEvaluator();
75
76    // We try several different types when searching for appropriate setter/getter functions.
77    // The caller may have supplied values in a type that does not match the setter/getter
78    // functions (such as the integers 0 and 1 to represent floating point values for alpha).
79    // Also, the use of generics in constructors means that we end up with the Object versions
80    // of primitive types (Float vs. float). But most likely, the setter/getter functions
81    // will take primitive types instead.
82    // So we supply an ordered array of other types to try before giving up.
83    private static Class[] FLOAT_VARIANTS = {float.class, Float.class, double.class, int.class,
84            Double.class, Integer.class};
85    private static Class[] INTEGER_VARIANTS = {int.class, Integer.class, float.class, double.class,
86            Float.class, Double.class};
87    private static Class[] DOUBLE_VARIANTS = {double.class, Double.class, float.class, int.class,
88            Float.class, Integer.class};
89
90    // These maps hold all property entries for a particular class. This map
91    // is used to speed up property/setter/getter lookups for a given class/property
92    // combination. No need to use reflection on the combination more than once.
93    private static final HashMap<Class, HashMap<String, Method>> sSetterPropertyMap =
94            new HashMap<Class, HashMap<String, Method>>();
95    private static final HashMap<Class, HashMap<String, Method>> sGetterPropertyMap =
96            new HashMap<Class, HashMap<String, Method>>();
97
98    // This lock is used to ensure that only one thread is accessing the property maps
99    // at a time.
100    private ReentrantReadWriteLock propertyMapLock = new ReentrantReadWriteLock();
101
102    // Used to pass single value to varargs parameter in setter invocation
103    private Object[] mTmpValueArray = new Object[1];
104
105    /**
106     * The type evaluator used to calculate the animated values. This evaluator is determined
107     * automatically based on the type of the start/end objects passed into the constructor,
108     * but the system only knows about the primitive types int, double, and float. Any other
109     * type will need to set the evaluator to a custom evaluator for that type.
110     */
111    private TypeEvaluator mEvaluator;
112
113    /**
114     * The value most recently calculated by calculateValue(). This is set during
115     * that function and might be retrieved later either by ValueAnimator.animatedValue() or
116     * by the property-setting logic in ObjectAnimator.animatedValue().
117     */
118    private Object mAnimatedValue;
119
120    /**
121     * Internal utility constructor, used by the factory methods to set the property name.
122     * @param propertyName The name of the property for this holder.
123     */
124    private PropertyValuesHolder(String propertyName) {
125        mPropertyName = propertyName;
126    }
127
128    /**
129     * Constructs and returns a PropertyValuesHolder with a given property name and
130     * set of int values.
131     * @param propertyName The name of the property being animated.
132     * @param values The values that the named property will animate between.
133     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
134     */
135    public static PropertyValuesHolder ofInt(String propertyName, int... values) {
136        PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName);
137        pvh.setIntValues(values);
138        return pvh;
139    }
140
141    /**
142     * Constructs and returns a PropertyValuesHolder with a given property name and
143     * set of float values.
144     * @param propertyName The name of the property being animated.
145     * @param values The values that the named property will animate between.
146     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
147     */
148    public static PropertyValuesHolder ofFloat(String propertyName, float... values) {
149        PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName);
150        pvh.setFloatValues(values);
151        return pvh;
152    }
153
154    /**
155     * Constructs and returns a PropertyValuesHolder with a given property name and
156     * set of double values.
157     * @param propertyName The name of the property being animated.
158     * @param values The values that the named property will animate between.
159     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
160     */
161    public static PropertyValuesHolder ofDouble(String propertyName, double... values) {
162        PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName);
163        pvh.setDoubleValues(values);
164        return pvh;
165    }
166
167    /**
168     * Constructs and returns a PropertyValuesHolder with a given property name and
169     * set of long values.
170     * @param propertyName The name of the property being animated.
171     * @param values The values that the named property will animate between.
172     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
173     */
174    public static PropertyValuesHolder ofLong(String propertyName, long... values) {
175        PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName);
176        pvh.setLongValues(values);
177        return pvh;
178    }
179
180    /**
181     * Constructs and returns a PropertyValuesHolder with a given property name and
182     * set of Object values. This variant also takes a TypeEvaluator because the system
183     * cannot interpolate between objects of unknown type.
184     *
185     * @param propertyName The name of the property being animated.
186     * @param evaluator A TypeEvaluator that will be called on each animation frame to
187     * provide the ncessry interpolation between the Object values to derive the animated
188     * value.
189     * @param values The values that the named property will animate between.
190     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
191     */
192    public static PropertyValuesHolder ofObject(String propertyName, TypeEvaluator evaluator,
193            Object... values) {
194        PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName);
195        pvh.setObjectValues(values);
196        pvh.setEvaluator(evaluator);
197        return pvh;
198    }
199
200    /**
201     * Constructs and returns a PropertyValuesHolder object with the specified property name and set
202     * of values. These values can be of any type, but the type should be consistent so that
203     * an appropriate {@link android.animation.TypeEvaluator} can be found that matches
204     * the common type.
205     * <p>If there is only one value, it is assumed to be the end value of an animation,
206     * and an initial value will be derived, if possible, by calling a getter function
207     * on the object. Also, if any value is null, the value will be filled in when the animation
208     * starts in the same way. This mechanism of automatically getting null values only works
209     * if the PropertyValuesHolder object is used in conjunction
210     * {@link ObjectAnimator}, and with a getter function either
211     * derived automatically from <code>propertyName</code> or set explicitly via
212     * {@link #setGetter(java.lang.reflect.Method)}, since otherwise PropertyValuesHolder has
213     * no way of determining what the value should be.
214     * @param propertyName The name of the property associated with this set of values. This
215     * can be the actual property name to be used when using a ObjectAnimator object, or
216     * just a name used to get animated values, such as if this object is used with an
217     * ValueAnimator object.
218     * @param values The set of values to animate between.
219     */
220    public static PropertyValuesHolder ofKeyframe(String propertyName, Keyframe... values) {
221        PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName);
222        pvh.setKeyframes(values);
223        return pvh;
224    }
225
226    /**
227     * Set the animated values for this object to this set of ints.
228     * If there is only one value, it is assumed to be the end value of an animation,
229     * and an initial value will be derived, if possible, by calling a getter function
230     * on the object. Also, if any value is null, the value will be filled in when the animation
231     * starts in the same way. This mechanism of automatically getting null values only works
232     * if the PropertyValuesHolder object is used in conjunction
233     * {@link ObjectAnimator}, and with a getter function either
234     * derived automatically from <code>propertyName</code> or set explicitly via
235     * {@link #setGetter(java.lang.reflect.Method)}, since otherwise PropertyValuesHolder has
236     * no way of determining what the value should be.
237     *
238     * @param values One or more values that the animation will animate between.
239     */
240    public void setIntValues(int... values) {
241        mValueType = int.class;
242        mKeyframeSet = KeyframeSet.ofInt(values);
243    }
244
245    /**
246     * Set the animated values for this object to this set of floats.
247     * If there is only one value, it is assumed to be the end value of an animation,
248     * and an initial value will be derived, if possible, by calling a getter function
249     * on the object. Also, if any value is null, the value will be filled in when the animation
250     * starts in the same way. This mechanism of automatically getting null values only works
251     * if the PropertyValuesHolder object is used in conjunction
252     * {@link ObjectAnimator}, and with a getter function either
253     * derived automatically from <code>propertyName</code> or set explicitly via
254     * {@link #setGetter(java.lang.reflect.Method)}, since otherwise PropertyValuesHolder has
255     * no way of determining what the value should be.
256     *
257     * @param values One or more values that the animation will animate between.
258     */
259    public void setFloatValues(float... values) {
260        mValueType = float.class;
261        mKeyframeSet = KeyframeSet.ofFloat(values);
262    }
263
264    /**
265     * Set the animated values for this object to this set of doubles.
266     * If there is only one value, it is assumed to be the end value of an animation,
267     * and an initial value will be derived, if possible, by calling a getter function
268     * on the object. Also, if any value is null, the value will be filled in when the animation
269     * starts in the same way. This mechanism of automatically getting null values only works
270     * if the PropertyValuesHolder object is used in conjunction
271     * {@link ObjectAnimator}, and with a getter function either
272     * derived automatically from <code>propertyName</code> or set explicitly via
273     * {@link #setGetter(java.lang.reflect.Method)}, since otherwise PropertyValuesHolder has
274     * no way of determining what the value should be.
275     *
276     * @param values One or more values that the animation will animate between.
277     */
278    public void setDoubleValues(double... values) {
279        mValueType = double.class;
280        mKeyframeSet = KeyframeSet.ofDouble(values);
281    }
282
283    /**
284     * Set the animated values for this object to this set of longs.
285     * If there is only one value, it is assumed to be the end value of an animation,
286     * and an initial value will be derived, if possible, by calling a getter function
287     * on the object. Also, if any value is null, the value will be filled in when the animation
288     * starts in the same way. This mechanism of automatically getting null values only works
289     * if the PropertyValuesHolder object is used in conjunction
290     * {@link ObjectAnimator}, and with a getter function either
291     * derived automatically from <code>propertyName</code> or set explicitly via
292     * {@link #setGetter(java.lang.reflect.Method)}, since otherwise PropertyValuesHolder has
293     * no way of determining what the value should be.
294     *
295     * @param values One or more values that the animation will animate between.
296     */
297    public void setLongValues(long... values) {
298        mValueType = long.class;
299        mKeyframeSet = KeyframeSet.ofLong(values);
300    }
301
302    /**
303     * Set the animated values for this object to this set of Keyframes.
304     *
305     * @param values One or more values that the animation will animate between.
306     */
307    public void setKeyframes(Keyframe... values) {
308        int numKeyframes = values.length;
309        Keyframe keyframes[] = new Keyframe[Math.max(numKeyframes,2)];
310        mValueType = ((Keyframe)values[0]).getType();
311        for (int i = 0; i < numKeyframes; ++i) {
312            keyframes[i] = (Keyframe)values[i];
313        }
314        mKeyframeSet = new KeyframeSet(keyframes);
315    }
316
317    /**
318     * Set the animated values for this object to this set of Objects.
319     * If there is only one value, it is assumed to be the end value of an animation,
320     * and an initial value will be derived, if possible, by calling a getter function
321     * on the object. Also, if any value is null, the value will be filled in when the animation
322     * starts in the same way. This mechanism of automatically getting null values only works
323     * if the PropertyValuesHolder object is used in conjunction
324     * {@link ObjectAnimator}, and with a getter function either
325     * derived automatically from <code>propertyName</code> or set explicitly via
326     * {@link #setGetter(java.lang.reflect.Method)}, since otherwise PropertyValuesHolder has
327     * no way of determining what the value should be.
328     *
329     * @param values One or more values that the animation will animate between.
330     */
331    public void setObjectValues(Object... values) {
332        mValueType = values[0].getClass();
333        mKeyframeSet = KeyframeSet.ofObject(values);
334    }
335
336    /**
337     * Sets the values being animated between.
338     * If there is only one value, it is assumed to be the end value of an animation,
339     * and an initial value will be derived, if possible, by calling a getter function
340     * on the object. Also, if any value is null, the value will be filled in when the animation
341     * starts in the same way. This mechanism of automatically getting null values only works
342     * if the PropertyValuesHolder object is used in conjunction
343     * {@link ObjectAnimator}, and with a getter function either
344     * derived automatically from <code>propertyName</code> or set explicitly via
345     * {@link #setGetter(java.lang.reflect.Method)}, since otherwise PropertyValuesHolder has
346     * no way of determining what the value should be.
347     * @param values The set of values to animate between.
348     */
349    /*
350    public void setValues(T... values) {
351        int numKeyframes = values.length;
352        for (int i = 0; i < numKeyframes; ++i) {
353            if (values[i] != null) {
354                Class thisValueType = values[i].getClass();
355                if (mValueType == null) {
356                    mValueType = thisValueType;
357                } else {
358                    if (thisValueType != mValueType) {
359                        if (mValueType == Integer.class &&
360                                (thisValueType == Float.class || thisValueType == Double.class)) {
361                            mValueType = thisValueType;
362                        } else if (mValueType == Float.class && thisValueType == Double.class) {
363                            mValueType = thisValueType;
364                        }
365                    }
366                }
367            }
368        }
369        Keyframe keyframes[] = new Keyframe[Math.max(numKeyframes,2)];
370        if (mValueType.equals(Keyframe.class)) {
371            mValueType = ((Keyframe)values[0]).getType();
372            for (int i = 0; i < numKeyframes; ++i) {
373                keyframes[i] = (Keyframe)values[i];
374            }
375        } else {
376            if (numKeyframes == 1) {
377                keyframes[0] = new Keyframe(0f, (Object) null);
378                keyframes[1] = new Keyframe(1f, values[0]);
379            } else {
380                keyframes[0] = new Keyframe(0f, values[0]);
381                for (int i = 1; i < numKeyframes; ++i) {
382                    if (values[i] != null && (values[i].getClass() != mValueType)) {
383
384                    }
385                    keyframes[i] = new Keyframe((float) i / (numKeyframes - 1), values[i]);
386                }
387            }
388        }
389        mKeyframeSet = new KeyframeSet(keyframes);
390    }
391    */
392
393
394
395    /**
396     * Determine the setter or getter function using the JavaBeans convention of setFoo or
397     * getFoo for a property named 'foo'. This function figures out what the name of the
398     * function should be and uses reflection to find the Method with that name on the
399     * target object.
400     *
401     * @param targetClass The class to search for the method
402     * @param prefix "set" or "get", depending on whether we need a setter or getter.
403     * @param valueType The type of the parameter (in the case of a setter). This type
404     * is derived from the values set on this PropertyValuesHolder. This type is used as
405     * a first guess at the parameter type, but we check for methods with several different
406     * types to avoid problems with slight mis-matches between supplied values and actual
407     * value types used on the setter.
408     * @return Method the method associated with mPropertyName.
409     */
410    private Method getPropertyFunction(Class targetClass, String prefix, Class valueType) {
411        // TODO: faster implementation...
412        Method returnVal = null;
413        String firstLetter = mPropertyName.substring(0, 1);
414        String theRest = mPropertyName.substring(1);
415        firstLetter = firstLetter.toUpperCase();
416        String methodName = prefix + firstLetter + theRest;
417        Class args[] = null;
418        if (valueType == null) {
419            try {
420                returnVal = targetClass.getMethod(methodName, args);
421            } catch (NoSuchMethodException e) {
422                Log.e("PropertyValuesHolder",
423                        "Couldn't find no-arg method for property " + mPropertyName + ": " + e);
424            }
425        } else {
426            args = new Class[1];
427            Class typeVariants[];
428            if (mValueType.equals(Float.class)) {
429                typeVariants = FLOAT_VARIANTS;
430            } else if (mValueType.equals(Integer.class)) {
431                typeVariants = INTEGER_VARIANTS;
432            } else if (mValueType.equals(Double.class)) {
433                typeVariants = DOUBLE_VARIANTS;
434            } else {
435                typeVariants = new Class[1];
436                typeVariants[0] = mValueType;
437            }
438            for (Class typeVariant : typeVariants) {
439                args[0] = typeVariant;
440                try {
441                    returnVal = targetClass.getMethod(methodName, args);
442                    // change the value type to suit
443                    mValueType = typeVariant;
444                    return returnVal;
445                } catch (NoSuchMethodException e) {
446                    // Swallow the error and keep trying other variants
447                }
448            }
449            // If we got here, then no appropriate function was found
450            Log.e("PropertyValuesHolder",
451                    "Couldn't find setter/getter for property " + mPropertyName +
452                            "with value type "+ mValueType);
453        }
454
455        return returnVal;
456    }
457
458
459    /**
460     * Returns the setter or getter requested. This utility function checks whether the
461     * requested method exists in the propertyMapMap cache. If not, it calls another
462     * utility function to request the Method from the targetClass directly.
463     * @param targetClass The Class on which the requested method should exist.
464     * @param propertyMapMap The cache of setters/getters derived so far.
465     * @param prefix "set" or "get", for the setter or getter.
466     * @param valueType The type of parameter passed into the method (null for getter).
467     * @return Method the method associated with mPropertyName.
468     */
469    private Method setupSetterOrGetter(Class targetClass,
470            HashMap<Class, HashMap<String, Method>> propertyMapMap,
471            String prefix, Class valueType) {
472        Method setterOrGetter = null;
473        try {
474            // Have to lock property map prior to reading it, to guard against
475            // another thread putting something in there after we've checked it
476            // but before we've added an entry to it
477            // TODO: can we store the setter/getter per Class instead of per Object?
478            propertyMapLock.writeLock().lock();
479            HashMap<String, Method> propertyMap = propertyMapMap.get(targetClass);
480            if (propertyMap != null) {
481                setterOrGetter = propertyMap.get(mPropertyName);
482            }
483            if (setterOrGetter == null) {
484                setterOrGetter = getPropertyFunction(targetClass, prefix, valueType);
485                if (propertyMap == null) {
486                    propertyMap = new HashMap<String, Method>();
487                    propertyMapMap.put(targetClass, propertyMap);
488                }
489                propertyMap.put(mPropertyName, setterOrGetter);
490            }
491        } finally {
492            propertyMapLock.writeLock().unlock();
493        }
494        return setterOrGetter;
495    }
496
497    /**
498     * Utility function to get the setter from targetClass
499     * @param targetClass The Class on which the requested method should exist.
500     */
501    private void setupSetter(Class targetClass) {
502        mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", mValueType);
503    }
504
505    /**
506     * Utility function to get the getter from targetClass
507     */
508    private void setupGetter(Class targetClass) {
509        mGetter = setupSetterOrGetter(targetClass, sGetterPropertyMap, "get", null);
510    }
511
512    /**
513     * Internal function (called from ObjectAnimator) to set up the setter and getter
514     * prior to running the animation. If the setter has not been manually set for this
515     * object, it will be derived automatically given the property name, target object, and
516     * types of values supplied. If no getter has been set, it will be supplied iff any of the
517     * supplied values was null. If there is a null value, then the getter (supplied or derived)
518     * will be called to set those null values to the current value of the property
519     * on the target object.
520     * @param target The object on which the setter (and possibly getter) exist.
521     */
522    void setupSetterAndGetter(Object target) {
523        Class targetClass = target.getClass();
524        if (mSetter == null) {
525            setupSetter(targetClass);
526        }
527        for (Keyframe kf : mKeyframeSet.mKeyframes) {
528            if (kf.getValue() == null) {
529                if (mGetter == null) {
530                    setupGetter(targetClass);
531                }
532                try {
533                    kf.setValue(mGetter.invoke(target));
534                } catch (InvocationTargetException e) {
535                    Log.e("PropertyValuesHolder", e.toString());
536                } catch (IllegalAccessException e) {
537                    Log.e("PropertyValuesHolder", e.toString());
538                }
539            }
540        }
541    }
542
543    /**
544     * Utility function to set the value stored in a particular Keyframe. The value used is
545     * whatever the value is for the property name specified in the keyframe on the target object.
546     *
547     * @param target The target object from which the current value should be extracted.
548     * @param kf The keyframe which holds the property name and value.
549     */
550    private void setupValue(Object target, Keyframe kf) {
551        try {
552            if (mGetter == null) {
553                Class targetClass = target.getClass();
554                setupGetter(targetClass);
555            }
556            kf.setValue(mGetter.invoke(target));
557        } catch (InvocationTargetException e) {
558            Log.e("PropertyValuesHolder", e.toString());
559        } catch (IllegalAccessException e) {
560            Log.e("PropertyValuesHolder", e.toString());
561        }
562    }
563
564    /**
565     * This function is called by ObjectAnimator when setting the start values for an animation.
566     * The start values are set according to the current values in the target object. The
567     * property whose value is extracted is whatever is specified by the propertyName of this
568     * PropertyValuesHolder object.
569     *
570     * @param target The object which holds the start values that should be set.
571     */
572    void setupStartValue(Object target) {
573        setupValue(target, mKeyframeSet.mKeyframes.get(0));
574    }
575
576    /**
577     * This function is called by ObjectAnimator when setting the end values for an animation.
578     * The end values are set according to the current values in the target object. The
579     * property whose value is extracted is whatever is specified by the propertyName of this
580     * PropertyValuesHolder object.
581     *
582     * @param target The object which holds the start values that should be set.
583     */
584    void setupEndValue(Object target) {
585        setupValue(target, mKeyframeSet.mKeyframes.get(mKeyframeSet.mKeyframes.size() - 1));
586    }
587
588    @Override
589    public PropertyValuesHolder clone() {
590        ArrayList<Keyframe> keyframes = mKeyframeSet.mKeyframes;
591        int numKeyframes = mKeyframeSet.mKeyframes.size();
592        Keyframe[] newKeyframes = new Keyframe[numKeyframes];
593        for (int i = 0; i < numKeyframes; ++i) {
594            newKeyframes[i] = keyframes.get(i).clone();
595        }
596        return PropertyValuesHolder.ofKeyframe(mPropertyName, newKeyframes);
597    }
598    /**
599     * Internal function to set the value on the target object, using the setter set up
600     * earlier on this PropertyValuesHolder object. This function is called by ObjectAnimator
601     * to handle turning the value calculated by ValueAnimator into a value set on the object
602     * according to the name of the property.
603     * @param target The target object on which the value is set
604     */
605    void setAnimatedValue(Object target) {
606        if (mSetter != null) {
607            try {
608                mTmpValueArray[0] = mAnimatedValue;
609                mSetter.invoke(target, mTmpValueArray);
610            } catch (InvocationTargetException e) {
611                Log.e("PropertyValuesHolder", e.toString());
612            } catch (IllegalAccessException e) {
613                Log.e("PropertyValuesHolder", e.toString());
614            }
615        }
616    }
617
618    /**
619     * Internal function, called by ValueAnimator, to set up the TypeEvaluator that will be used
620     * to calculate animated values.
621     */
622    void init() {
623        if (mEvaluator == null) {
624            mEvaluator = (mValueType == int.class || mValueType == Integer.class) ? sIntEvaluator :
625                (mValueType == double.class || mValueType == Double.class) ? sDoubleEvaluator :
626                        sFloatEvaluator;
627        }
628    }
629
630    /**
631     * The TypeEvaluator will the automatically determined based on the type of values
632     * supplied to PropertyValuesHolder. The evaluator can be manually set, however, if so
633     * desired. This may be important in cases where either the type of the values supplied
634     * do not match the way that they should be interpolated between, or if the values
635     * are of a custom type or one not currently understood by the animation system. Currently,
636     * only values of type float, double, and int (and their Object equivalents, Float, Double,
637     * and Integer) are  correctly interpolated; all other types require setting a TypeEvaluator.
638     * @param evaluator
639     */
640	public void setEvaluator(TypeEvaluator evaluator) {
641        mEvaluator = evaluator;
642    }
643
644    /**
645     * Function used to calculate the value according to the evaluator set up for
646     * this PropertyValuesHolder object. This function is called by ValueAnimator.animateValue().
647     *
648     * @param fraction The elapsed, interpolated fraction of the animation.
649     * @return The calculated value at this point in the animation.
650     */
651    Object calculateValue(float fraction) {
652        mAnimatedValue = mKeyframeSet.getValue(fraction, mEvaluator);
653        return mAnimatedValue;
654    }
655
656    /**
657     * Sets the <code>Method</code> that is called with the animated values calculated
658     * during the animation. Setting the setter method is an alternative to supplying a
659     * {@link #setPropertyName(String) propertyName} from which the method is derived. This
660     * approach is more direct, and is especially useful when a function must be called that does
661     * not correspond to the convention of <code>setName()</code>. For example, if a function
662     * called <code>offset()</code> is to be called with the animated values, there is no way
663     * to tell <code>ObjectAnimator</code> how to call that function simply through a property
664     * name, so a setter method should be supplied instead.
665     *
666     * <p>Note that the setter function must take the same parameter type as the
667     * <code>valueFrom</code> and <code>valueTo</code> properties, otherwise the call to
668     * the setter function will fail.</p>
669     *
670     * @param setter The setter method that should be called with the animated values.
671     */
672    public void setSetter(Method setter) {
673        mSetter = setter;
674    }
675
676    /**
677     * Gets the <code>Method</code> that is called with the animated values calculated
678     * during the animation.
679     */
680    public Method getSetter() {
681        return mSetter;
682    }
683
684    /**
685     * Sets the <code>Method</code> that is called to get unsupplied <code>valueFrom</code> or
686     * <code>valueTo</code> properties. Setting the getter method is an alternative to supplying a
687     * {@link #setPropertyName(String) propertyName} from which the method is derived. This
688     * approach is more direct, and is especially useful when a function must be called that does
689     * not correspond to the convention of <code>setName()</code>. For example, if a function
690     * called <code>offset()</code> is to be called to get an initial value, there is no way
691     * to tell <code>ObjectAnimator</code> how to call that function simply through a property
692     * name, so a getter method should be supplied instead.
693     *
694     * <p>Note that the getter method is only called whether supplied here or derived
695     * from the property name, if one of <code>valueFrom</code> or <code>valueTo</code> are
696     * null. If both of those values are non-null, then there is no need to get one of the
697     * values and the getter is not called.
698     *
699     * <p>Note that the getter function must return the same parameter type as the
700     * <code>valueFrom</code> and <code>valueTo</code> properties (whichever of them are
701     * non-null), otherwise the call to the getter function will fail.</p>
702     *
703     * @param getter The getter method that should be called to get initial animation values.
704     */
705    public void setGetter(Method getter) {
706        mGetter = getter;
707    }
708
709    /**
710     * Gets the <code>Method</code> that is called to get unsupplied <code>valueFrom</code> or
711     * <code>valueTo</code> properties.
712     */
713    public Method getGetter() {
714        return mGetter;
715    }
716
717    /**
718     * Sets the name of the property that will be animated. This name is used to derive
719     * a setter function that will be called to set animated values.
720     * For example, a property name of <code>foo</code> will result
721     * in a call to the function <code>setFoo()</code> on the target object. If either
722     * <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will
723     * also be derived and called.
724     *
725     * <p>Note that the setter function derived from this property name
726     * must take the same parameter type as the
727     * <code>valueFrom</code> and <code>valueTo</code> properties, otherwise the call to
728     * the setter function will fail.</p>
729     *
730     * @param propertyName The name of the property being animated.
731     */
732    public void setPropertyName(String propertyName) {
733        mPropertyName = propertyName;
734    }
735
736    /**
737     * Gets the name of the property that will be animated. This name will be used to derive
738     * a setter function that will be called to set animated values.
739     * For example, a property name of <code>foo</code> will result
740     * in a call to the function <code>setFoo()</code> on the target object. If either
741     * <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will
742     * also be derived and called.
743     */
744    public String getPropertyName() {
745        return mPropertyName;
746    }
747
748    /**
749     * Internal function, called by ValueAnimator and ObjectAnimator, to retrieve the value
750     * most recently calculated in calculateValue().
751     * @return
752     */
753    Object getAnimatedValue() {
754        return mAnimatedValue;
755    }
756}