1d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase/*
2d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase * Copyright (C) 2010 The Android Open Source Project
3d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase *
4d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase * Licensed under the Apache License, Version 2.0 (the "License");
5d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase * you may not use this file except in compliance with the License.
6d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase * You may obtain a copy of the License at
7d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase *
8d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase *      http://www.apache.org/licenses/LICENSE-2.0
9d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase *
10d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase * Unless required by applicable law or agreed to in writing, software
11d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase * distributed under the License is distributed on an "AS IS" BASIS,
12d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase * See the License for the specific language governing permissions and
14d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase * limitations under the License.
15d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase */
16d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
17d953d08e9299072130d9f4411cbcf6678bbce822Chet Haasepackage android.animation;
18d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
19c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mountimport android.graphics.Path;
20c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mountimport android.graphics.PointF;
21b39f051631250c49936a475d0e64584afb7f1b93Chet Haaseimport android.util.FloatProperty;
22b39f051631250c49936a475d0e64584afb7f1b93Chet Haaseimport android.util.IntProperty;
23d953d08e9299072130d9f4411cbcf6678bbce822Chet Haaseimport android.util.Log;
24766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liuimport android.util.PathParser;
25b39f051631250c49936a475d0e64584afb7f1b93Chet Haaseimport android.util.Property;
26d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
27d953d08e9299072130d9f4411cbcf6678bbce822Chet Haaseimport java.lang.reflect.InvocationTargetException;
28d953d08e9299072130d9f4411cbcf6678bbce822Chet Haaseimport java.lang.reflect.Method;
29d953d08e9299072130d9f4411cbcf6678bbce822Chet Haaseimport java.util.HashMap;
30d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyarimport java.util.List;
31d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
32d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase/**
3321cd1389d2ef218b20994b617c57af120841a57fChet Haase * This class holds information about a property and the values that that property
3421cd1389d2ef218b20994b617c57af120841a57fChet Haase * should take on during an animation. PropertyValuesHolder objects can be used to create
35a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * animations with ValueAnimator or ObjectAnimator that operate on several different properties
3621cd1389d2ef218b20994b617c57af120841a57fChet Haase * in parallel.
37d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase */
382794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haasepublic class PropertyValuesHolder implements Cloneable {
39d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
40d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
41d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * The name of the property associated with the values. This need not be a real property,
42a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * unless this object is being used with ObjectAnimator. But this is the name by which
43a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * aniamted values are looked up with getAnimatedValue(String) in ValueAnimator.
44d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
456e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase    String mPropertyName;
46d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
47d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
48b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @hide
49b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     */
50b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    protected Property mProperty;
51b39f051631250c49936a475d0e64584afb7f1b93Chet Haase
52b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    /**
53a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * The setter function, if needed. ObjectAnimator hands off this functionality to
54d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * PropertyValuesHolder, since it holds all of the per-property information. This
5537f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase     * property is automatically
56a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * derived when the animation starts in setupSetterAndGetter() if using ObjectAnimator.
57d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
587c608f25d494c8a0a671e7373efbb47ca635367eChet Haase    Method mSetter = null;
59d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
60d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
61a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * The getter function, if needed. ObjectAnimator hands off this functionality to
62d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * PropertyValuesHolder, since it holds all of the per-property information. This
6337f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase     * property is automatically
64a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * derived when the animation starts in setupSetterAndGetter() if using ObjectAnimator.
65d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * The getter is only derived and used if one of the values is null.
66d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
67d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    private Method mGetter = null;
68d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
69d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
70d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * The type of values supplied. This information is used both in deriving the setter/getter
71d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * functions and in deriving the type of TypeEvaluator.
72d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
737c608f25d494c8a0a671e7373efbb47ca635367eChet Haase    Class mValueType;
74d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
75d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
76d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * The set of keyframes (time/value pairs) that define this animation.
77d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
78984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount    Keyframes mKeyframes = null;
79d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
80d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
81b2ab04ffb6894f399d5c9ceb15f64eb17b654426Chet Haase    // type evaluators for the primitive types handled by this implementation
82d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    private static final TypeEvaluator sIntEvaluator = new IntEvaluator();
83d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    private static final TypeEvaluator sFloatEvaluator = new FloatEvaluator();
84d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
85d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    // We try several different types when searching for appropriate setter/getter functions.
86d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    // The caller may have supplied values in a type that does not match the setter/getter
87d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    // functions (such as the integers 0 and 1 to represent floating point values for alpha).
88d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    // Also, the use of generics in constructors means that we end up with the Object versions
89d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    // of primitive types (Float vs. float). But most likely, the setter/getter functions
90d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    // will take primitive types instead.
91d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    // So we supply an ordered array of other types to try before giving up.
92d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    private static Class[] FLOAT_VARIANTS = {float.class, Float.class, double.class, int.class,
93d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            Double.class, Integer.class};
94d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    private static Class[] INTEGER_VARIANTS = {int.class, Integer.class, float.class, double.class,
95d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            Float.class, Double.class};
96d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    private static Class[] DOUBLE_VARIANTS = {double.class, Double.class, float.class, int.class,
97d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            Float.class, Integer.class};
98d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
99d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    // These maps hold all property entries for a particular class. This map
100d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    // is used to speed up property/setter/getter lookups for a given class/property
101d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    // combination. No need to use reflection on the combination more than once.
102d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    private static final HashMap<Class, HashMap<String, Method>> sSetterPropertyMap =
103d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            new HashMap<Class, HashMap<String, Method>>();
104d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    private static final HashMap<Class, HashMap<String, Method>> sGetterPropertyMap =
105d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            new HashMap<Class, HashMap<String, Method>>();
106d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
107d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    // Used to pass single value to varargs parameter in setter invocation
1086e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase    final Object[] mTmpValueArray = new Object[1];
109d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
110d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
111d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * The type evaluator used to calculate the animated values. This evaluator is determined
112d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * automatically based on the type of the start/end objects passed into the constructor,
113b2ab04ffb6894f399d5c9ceb15f64eb17b654426Chet Haase     * but the system only knows about the primitive types int and float. Any other
114d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * type will need to set the evaluator to a custom evaluator for that type.
115d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
116d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    private TypeEvaluator mEvaluator;
117d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
118d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
119d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * The value most recently calculated by calculateValue(). This is set during
120a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * that function and might be retrieved later either by ValueAnimator.animatedValue() or
121a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * by the property-setting logic in ObjectAnimator.animatedValue().
122d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
123d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    private Object mAnimatedValue;
124d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
125d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
12616d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount     * Converts from the source Object type to the setter Object type.
12716d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount     */
12816d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount    private TypeConverter mConverter;
12916d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount
13016d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount    /**
1312794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * Internal utility constructor, used by the factory methods to set the property name.
1322794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @param propertyName The name of the property for this holder.
133d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
1342794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    private PropertyValuesHolder(String propertyName) {
1352794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase        mPropertyName = propertyName;
1362794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    }
1372794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase
1382794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    /**
139b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * Internal utility constructor, used by the factory methods to set the property.
140b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @param property The property for this holder.
141b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     */
142b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    private PropertyValuesHolder(Property property) {
143b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        mProperty = property;
144b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        if (property != null) {
145b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            mPropertyName = property.getName();
146b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        }
147b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    }
148b39f051631250c49936a475d0e64584afb7f1b93Chet Haase
149b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    /**
1502794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * Constructs and returns a PropertyValuesHolder with a given property name and
1512794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * set of int values.
1522794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @param propertyName The name of the property being animated.
1532794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @param values The values that the named property will animate between.
1542794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
1552794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     */
1562794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    public static PropertyValuesHolder ofInt(String propertyName, int... values) {
157b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        return new IntPropertyValuesHolder(propertyName, values);
158b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    }
159b39f051631250c49936a475d0e64584afb7f1b93Chet Haase
160b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    /**
161b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * Constructs and returns a PropertyValuesHolder with a given property and
162b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * set of int values.
163b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @param property The property being animated. Should not be null.
164b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @param values The values that the property will animate between.
165b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
166b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     */
167b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    public static PropertyValuesHolder ofInt(Property<?, Integer> property, int... values) {
168b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        return new IntPropertyValuesHolder(property, values);
1692794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    }
1702794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase
1712794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    /**
1722794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * Constructs and returns a PropertyValuesHolder with a given property name and
1734eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * set of <code>int[]</code> values. At least two <code>int[]</code> values must be supplied,
1744eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * a start and end value. If more values are supplied, the values will be animated from the
1754eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * start, through all intermediate values to the end value. When used with ObjectAnimator,
1764eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * the elements of the array represent the parameters of the setter function.
1774eed52944c0fcb3afa7369aba60fb5c655580286George Mount     *
178c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * @param propertyName The name of the property being animated. Can also be the
179c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     *                     case-sensitive name of the entire setter method. Should not be null.
1804eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @param values The values that the property will animate between.
1814eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
1824eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @see IntArrayEvaluator#IntArrayEvaluator(int[])
1834eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @see ObjectAnimator#ofMultiInt(Object, String, TypeConverter, TypeEvaluator, Object[])
1844eed52944c0fcb3afa7369aba60fb5c655580286George Mount     */
1854eed52944c0fcb3afa7369aba60fb5c655580286George Mount    public static PropertyValuesHolder ofMultiInt(String propertyName, int[][] values) {
1864eed52944c0fcb3afa7369aba60fb5c655580286George Mount        if (values.length < 2) {
1874eed52944c0fcb3afa7369aba60fb5c655580286George Mount            throw new IllegalArgumentException("At least 2 values must be supplied");
1884eed52944c0fcb3afa7369aba60fb5c655580286George Mount        }
1894eed52944c0fcb3afa7369aba60fb5c655580286George Mount        int numParameters = 0;
1904eed52944c0fcb3afa7369aba60fb5c655580286George Mount        for (int i = 0; i < values.length; i++) {
1914eed52944c0fcb3afa7369aba60fb5c655580286George Mount            if (values[i] == null) {
1924eed52944c0fcb3afa7369aba60fb5c655580286George Mount                throw new IllegalArgumentException("values must not be null");
1934eed52944c0fcb3afa7369aba60fb5c655580286George Mount            }
1944eed52944c0fcb3afa7369aba60fb5c655580286George Mount            int length = values[i].length;
1954eed52944c0fcb3afa7369aba60fb5c655580286George Mount            if (i == 0) {
1964eed52944c0fcb3afa7369aba60fb5c655580286George Mount                numParameters = length;
1974eed52944c0fcb3afa7369aba60fb5c655580286George Mount            } else if (length != numParameters) {
1984eed52944c0fcb3afa7369aba60fb5c655580286George Mount                throw new IllegalArgumentException("Values must all have the same length");
1994eed52944c0fcb3afa7369aba60fb5c655580286George Mount            }
2004eed52944c0fcb3afa7369aba60fb5c655580286George Mount        }
2014eed52944c0fcb3afa7369aba60fb5c655580286George Mount        IntArrayEvaluator evaluator = new IntArrayEvaluator(new int[numParameters]);
2024eed52944c0fcb3afa7369aba60fb5c655580286George Mount        return new MultiIntValuesHolder(propertyName, null, evaluator, (Object[]) values);
2034eed52944c0fcb3afa7369aba60fb5c655580286George Mount    }
2044eed52944c0fcb3afa7369aba60fb5c655580286George Mount
2054eed52944c0fcb3afa7369aba60fb5c655580286George Mount    /**
206c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * Constructs and returns a PropertyValuesHolder with a given property name to use
207c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * as a multi-int setter. The values are animated along the path, with the first
208c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * parameter of the setter set to the x coordinate and the second set to the y coordinate.
209c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     *
210c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * @param propertyName The name of the property being animated. Can also be the
211c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     *                     case-sensitive name of the entire setter method. Should not be null.
212c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     *                     The setter must take exactly two <code>int</code> parameters.
213c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * @param path The Path along which the values should be animated.
214c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
215c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * @see ObjectAnimator#ofPropertyValuesHolder(Object, PropertyValuesHolder...)
216c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     */
217c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount    public static PropertyValuesHolder ofMultiInt(String propertyName, Path path) {
218984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        Keyframes keyframes = KeyframeSet.ofPath(path);
219c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount        PointFToIntArray converter = new PointFToIntArray();
220984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        return new MultiIntValuesHolder(propertyName, converter, null, keyframes);
221c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount    }
222c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount
223c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount    /**
2244eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * Constructs and returns a PropertyValuesHolder with a given property and
2254eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * set of Object values for use with ObjectAnimator multi-value setters. The Object
2264eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * values are converted to <code>int[]</code> using the converter.
2274eed52944c0fcb3afa7369aba60fb5c655580286George Mount     *
2284eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @param propertyName The property being animated or complete name of the setter.
2294eed52944c0fcb3afa7369aba60fb5c655580286George Mount     *                     Should not be null.
2304eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @param converter Used to convert the animated value to setter parameters.
2314eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @param evaluator A TypeEvaluator that will be called on each animation frame to
2324eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * provide the necessary interpolation between the Object values to derive the animated
2334eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * value.
2344eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @param values The values that the property will animate between.
2354eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
2364eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @see ObjectAnimator#ofMultiInt(Object, String, TypeConverter, TypeEvaluator, Object[])
2374eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @see ObjectAnimator#ofPropertyValuesHolder(Object, PropertyValuesHolder...)
2384eed52944c0fcb3afa7369aba60fb5c655580286George Mount     */
239d98f4ba86c02714d94ec3b6f35345cb0b04f7778George Mount    @SafeVarargs
2404eed52944c0fcb3afa7369aba60fb5c655580286George Mount    public static <V> PropertyValuesHolder ofMultiInt(String propertyName,
2414eed52944c0fcb3afa7369aba60fb5c655580286George Mount            TypeConverter<V, int[]> converter, TypeEvaluator<V> evaluator, V... values) {
2424eed52944c0fcb3afa7369aba60fb5c655580286George Mount        return new MultiIntValuesHolder(propertyName, converter, evaluator, values);
2434eed52944c0fcb3afa7369aba60fb5c655580286George Mount    }
2444eed52944c0fcb3afa7369aba60fb5c655580286George Mount
2454eed52944c0fcb3afa7369aba60fb5c655580286George Mount    /**
2464eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * Constructs and returns a PropertyValuesHolder object with the specified property name or
2474eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * setter name for use in a multi-int setter function using ObjectAnimator. The values can be
2484eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * of any type, but the type should be consistent so that the supplied
2494eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * {@link android.animation.TypeEvaluator} can be used to to evaluate the animated value. The
2504eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * <code>converter</code> converts the values to parameters in the setter function.
2514eed52944c0fcb3afa7369aba60fb5c655580286George Mount     *
2524eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * <p>At least two values must be supplied, a start and an end value.</p>
2534eed52944c0fcb3afa7369aba60fb5c655580286George Mount     *
2544eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @param propertyName The name of the property to associate with the set of values. This
2554eed52944c0fcb3afa7369aba60fb5c655580286George Mount     *                     may also be the complete name of a setter function.
2564eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @param converter    Converts <code>values</code> into int parameters for the setter.
2574eed52944c0fcb3afa7369aba60fb5c655580286George Mount     *                     Can be null if the Keyframes have int[] values.
2584eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @param evaluator    Used to interpolate between values.
2594eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @param values       The values at specific fractional times to evaluate between
2604eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @return A PropertyValuesHolder for a multi-int parameter setter.
2614eed52944c0fcb3afa7369aba60fb5c655580286George Mount     */
2624eed52944c0fcb3afa7369aba60fb5c655580286George Mount    public static <T> PropertyValuesHolder ofMultiInt(String propertyName,
2634eed52944c0fcb3afa7369aba60fb5c655580286George Mount            TypeConverter<T, int[]> converter, TypeEvaluator<T> evaluator, Keyframe... values) {
2644eed52944c0fcb3afa7369aba60fb5c655580286George Mount        KeyframeSet keyframeSet = KeyframeSet.ofKeyframe(values);
2654eed52944c0fcb3afa7369aba60fb5c655580286George Mount        return new MultiIntValuesHolder(propertyName, converter, evaluator, keyframeSet);
2664eed52944c0fcb3afa7369aba60fb5c655580286George Mount    }
2674eed52944c0fcb3afa7369aba60fb5c655580286George Mount
2684eed52944c0fcb3afa7369aba60fb5c655580286George Mount    /**
2694eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * Constructs and returns a PropertyValuesHolder with a given property name and
2702794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * set of float values.
2712794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @param propertyName The name of the property being animated.
2722794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @param values The values that the named property will animate between.
2732794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
2742794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     */
2752794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    public static PropertyValuesHolder ofFloat(String propertyName, float... values) {
276b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        return new FloatPropertyValuesHolder(propertyName, values);
277b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    }
278b39f051631250c49936a475d0e64584afb7f1b93Chet Haase
279b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    /**
280b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * Constructs and returns a PropertyValuesHolder with a given property and
281b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * set of float values.
282b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @param property The property being animated. Should not be null.
283b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @param values The values that the property will animate between.
284b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
285b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     */
286b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    public static PropertyValuesHolder ofFloat(Property<?, Float> property, float... values) {
287b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        return new FloatPropertyValuesHolder(property, values);
2882794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    }
2892794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase
2902794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    /**
2912794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * Constructs and returns a PropertyValuesHolder with a given property name and
2924eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * set of <code>float[]</code> values. At least two <code>float[]</code> values must be supplied,
2934eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * a start and end value. If more values are supplied, the values will be animated from the
2944eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * start, through all intermediate values to the end value. When used with ObjectAnimator,
2954eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * the elements of the array represent the parameters of the setter function.
2964eed52944c0fcb3afa7369aba60fb5c655580286George Mount     *
297c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * @param propertyName The name of the property being animated. Can also be the
298c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     *                     case-sensitive name of the entire setter method. Should not be null.
2994eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @param values The values that the property will animate between.
3004eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
3014eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @see FloatArrayEvaluator#FloatArrayEvaluator(float[])
3024eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @see ObjectAnimator#ofMultiFloat(Object, String, TypeConverter, TypeEvaluator, Object[])
3034eed52944c0fcb3afa7369aba60fb5c655580286George Mount     */
3044eed52944c0fcb3afa7369aba60fb5c655580286George Mount    public static PropertyValuesHolder ofMultiFloat(String propertyName, float[][] values) {
3054eed52944c0fcb3afa7369aba60fb5c655580286George Mount        if (values.length < 2) {
3064eed52944c0fcb3afa7369aba60fb5c655580286George Mount            throw new IllegalArgumentException("At least 2 values must be supplied");
3074eed52944c0fcb3afa7369aba60fb5c655580286George Mount        }
3084eed52944c0fcb3afa7369aba60fb5c655580286George Mount        int numParameters = 0;
3094eed52944c0fcb3afa7369aba60fb5c655580286George Mount        for (int i = 0; i < values.length; i++) {
3104eed52944c0fcb3afa7369aba60fb5c655580286George Mount            if (values[i] == null) {
3114eed52944c0fcb3afa7369aba60fb5c655580286George Mount                throw new IllegalArgumentException("values must not be null");
3124eed52944c0fcb3afa7369aba60fb5c655580286George Mount            }
3134eed52944c0fcb3afa7369aba60fb5c655580286George Mount            int length = values[i].length;
3144eed52944c0fcb3afa7369aba60fb5c655580286George Mount            if (i == 0) {
3154eed52944c0fcb3afa7369aba60fb5c655580286George Mount                numParameters = length;
3164eed52944c0fcb3afa7369aba60fb5c655580286George Mount            } else if (length != numParameters) {
3174eed52944c0fcb3afa7369aba60fb5c655580286George Mount                throw new IllegalArgumentException("Values must all have the same length");
3184eed52944c0fcb3afa7369aba60fb5c655580286George Mount            }
3194eed52944c0fcb3afa7369aba60fb5c655580286George Mount        }
3204eed52944c0fcb3afa7369aba60fb5c655580286George Mount        FloatArrayEvaluator evaluator = new FloatArrayEvaluator(new float[numParameters]);
3214eed52944c0fcb3afa7369aba60fb5c655580286George Mount        return new MultiFloatValuesHolder(propertyName, null, evaluator, (Object[]) values);
3224eed52944c0fcb3afa7369aba60fb5c655580286George Mount    }
3234eed52944c0fcb3afa7369aba60fb5c655580286George Mount
3244eed52944c0fcb3afa7369aba60fb5c655580286George Mount    /**
325c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * Constructs and returns a PropertyValuesHolder with a given property name to use
326c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * as a multi-float setter. The values are animated along the path, with the first
327c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * parameter of the setter set to the x coordinate and the second set to the y coordinate.
328c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     *
329c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * @param propertyName The name of the property being animated. Can also be the
330c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     *                     case-sensitive name of the entire setter method. Should not be null.
331c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     *                     The setter must take exactly two <code>float</code> parameters.
332c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * @param path The Path along which the values should be animated.
333c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
334c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * @see ObjectAnimator#ofPropertyValuesHolder(Object, PropertyValuesHolder...)
335c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     */
336c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount    public static PropertyValuesHolder ofMultiFloat(String propertyName, Path path) {
337984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        Keyframes keyframes = KeyframeSet.ofPath(path);
338c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount        PointFToFloatArray converter = new PointFToFloatArray();
339984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        return new MultiFloatValuesHolder(propertyName, converter, null, keyframes);
340c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount    }
341c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount
342c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount    /**
3434eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * Constructs and returns a PropertyValuesHolder with a given property and
3444eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * set of Object values for use with ObjectAnimator multi-value setters. The Object
3454eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * values are converted to <code>float[]</code> using the converter.
3464eed52944c0fcb3afa7369aba60fb5c655580286George Mount     *
3474eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @param propertyName The property being animated or complete name of the setter.
3484eed52944c0fcb3afa7369aba60fb5c655580286George Mount     *                     Should not be null.
3494eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @param converter Used to convert the animated value to setter parameters.
3504eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @param evaluator A TypeEvaluator that will be called on each animation frame to
3514eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * provide the necessary interpolation between the Object values to derive the animated
3524eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * value.
3534eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @param values The values that the property will animate between.
3544eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
3554eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @see ObjectAnimator#ofMultiFloat(Object, String, TypeConverter, TypeEvaluator, Object[])
3564eed52944c0fcb3afa7369aba60fb5c655580286George Mount     */
357d98f4ba86c02714d94ec3b6f35345cb0b04f7778George Mount    @SafeVarargs
3584eed52944c0fcb3afa7369aba60fb5c655580286George Mount    public static <V> PropertyValuesHolder ofMultiFloat(String propertyName,
3594eed52944c0fcb3afa7369aba60fb5c655580286George Mount            TypeConverter<V, float[]> converter, TypeEvaluator<V> evaluator, V... values) {
3604eed52944c0fcb3afa7369aba60fb5c655580286George Mount        return new MultiFloatValuesHolder(propertyName, converter, evaluator, values);
3614eed52944c0fcb3afa7369aba60fb5c655580286George Mount    }
3624eed52944c0fcb3afa7369aba60fb5c655580286George Mount
3634eed52944c0fcb3afa7369aba60fb5c655580286George Mount    /**
3644eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * Constructs and returns a PropertyValuesHolder object with the specified property name or
3654eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * setter name for use in a multi-float setter function using ObjectAnimator. The values can be
3664eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * of any type, but the type should be consistent so that the supplied
3674eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * {@link android.animation.TypeEvaluator} can be used to to evaluate the animated value. The
3684eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * <code>converter</code> converts the values to parameters in the setter function.
3694eed52944c0fcb3afa7369aba60fb5c655580286George Mount     *
3704eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * <p>At least two values must be supplied, a start and an end value.</p>
3714eed52944c0fcb3afa7369aba60fb5c655580286George Mount     *
3724eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @param propertyName The name of the property to associate with the set of values. This
3734eed52944c0fcb3afa7369aba60fb5c655580286George Mount     *                     may also be the complete name of a setter function.
3744eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @param converter    Converts <code>values</code> into float parameters for the setter.
3754eed52944c0fcb3afa7369aba60fb5c655580286George Mount     *                     Can be null if the Keyframes have float[] values.
3764eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @param evaluator    Used to interpolate between values.
3774eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @param values       The values at specific fractional times to evaluate between
3784eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * @return A PropertyValuesHolder for a multi-float parameter setter.
3794eed52944c0fcb3afa7369aba60fb5c655580286George Mount     */
3804eed52944c0fcb3afa7369aba60fb5c655580286George Mount    public static <T> PropertyValuesHolder ofMultiFloat(String propertyName,
3814eed52944c0fcb3afa7369aba60fb5c655580286George Mount            TypeConverter<T, float[]> converter, TypeEvaluator<T> evaluator, Keyframe... values) {
3824eed52944c0fcb3afa7369aba60fb5c655580286George Mount        KeyframeSet keyframeSet = KeyframeSet.ofKeyframe(values);
3834eed52944c0fcb3afa7369aba60fb5c655580286George Mount        return new MultiFloatValuesHolder(propertyName, converter, evaluator, keyframeSet);
3844eed52944c0fcb3afa7369aba60fb5c655580286George Mount    }
3854eed52944c0fcb3afa7369aba60fb5c655580286George Mount
3864eed52944c0fcb3afa7369aba60fb5c655580286George Mount    /**
3874eed52944c0fcb3afa7369aba60fb5c655580286George Mount     * Constructs and returns a PropertyValuesHolder with a given property name and
3882794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * set of Object values. This variant also takes a TypeEvaluator because the system
389b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * cannot automatically interpolate between objects of unknown type.
3902794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     *
391fa21bdfd5a8a5da3ec0530f7cc884994f92dc597Chet Haase     * <p><strong>Note:</strong> The Object values are stored as references to the original
392fa21bdfd5a8a5da3ec0530f7cc884994f92dc597Chet Haase     * objects, which means that changes to those objects after this method is called will
393fa21bdfd5a8a5da3ec0530f7cc884994f92dc597Chet Haase     * affect the values on the PropertyValuesHolder. If the objects will be mutated externally
394fa21bdfd5a8a5da3ec0530f7cc884994f92dc597Chet Haase     * after this method is called, callers should pass a copy of those objects instead.
395fa21bdfd5a8a5da3ec0530f7cc884994f92dc597Chet Haase     *
3962794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @param propertyName The name of the property being animated.
3972794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @param evaluator A TypeEvaluator that will be called on each animation frame to
398b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * provide the necessary interpolation between the Object values to derive the animated
3992794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * value.
4002794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @param values The values that the named property will animate between.
4012794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
4022794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     */
4032794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    public static PropertyValuesHolder ofObject(String propertyName, TypeEvaluator evaluator,
4042794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase            Object... values) {
4052794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase        PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName);
4062794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase        pvh.setObjectValues(values);
4072794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase        pvh.setEvaluator(evaluator);
4082794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase        return pvh;
409d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
410d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
411d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
412c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * Constructs and returns a PropertyValuesHolder with a given property name and
413c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * a Path along which the values should be animated. This variant supports a
414c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * <code>TypeConverter</code> to convert from <code>PointF</code> to the target
415c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * type.
416c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     *
417984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount     * <p>The PointF passed to <code>converter</code> or <code>property</code>, if
418984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount     * <code>converter</code> is <code>null</code>, is reused on each animation frame and should
419984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount     * not be stored by the setter or TypeConverter.</p>
420984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount     *
421c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * @param propertyName The name of the property being animated.
422c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * @param converter Converts a PointF to the type associated with the setter. May be
423c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     *                  null if conversion is unnecessary.
424c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * @param path The Path along which the values should be animated.
425c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
426c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     */
427c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount    public static PropertyValuesHolder ofObject(String propertyName,
428c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount            TypeConverter<PointF, ?> converter, Path path) {
429984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName);
430984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        pvh.mKeyframes = KeyframeSet.ofPath(path);
431984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        pvh.mValueType = PointF.class;
432c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount        pvh.setConverter(converter);
433c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount        return pvh;
434c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount    }
435c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount
436c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount    /**
437b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * Constructs and returns a PropertyValuesHolder with a given property and
438b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * set of Object values. This variant also takes a TypeEvaluator because the system
439b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * cannot automatically interpolate between objects of unknown type.
440b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     *
441fa21bdfd5a8a5da3ec0530f7cc884994f92dc597Chet Haase     * <p><strong>Note:</strong> The Object values are stored as references to the original
442fa21bdfd5a8a5da3ec0530f7cc884994f92dc597Chet Haase     * objects, which means that changes to those objects after this method is called will
443fa21bdfd5a8a5da3ec0530f7cc884994f92dc597Chet Haase     * affect the values on the PropertyValuesHolder. If the objects will be mutated externally
444fa21bdfd5a8a5da3ec0530f7cc884994f92dc597Chet Haase     * after this method is called, callers should pass a copy of those objects instead.
445fa21bdfd5a8a5da3ec0530f7cc884994f92dc597Chet Haase     *
446b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @param property The property being animated. Should not be null.
447b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @param evaluator A TypeEvaluator that will be called on each animation frame to
448b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * provide the necessary interpolation between the Object values to derive the animated
449b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * value.
450b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @param values The values that the property will animate between.
451b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
452b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     */
453d98f4ba86c02714d94ec3b6f35345cb0b04f7778George Mount    @SafeVarargs
454b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    public static <V> PropertyValuesHolder ofObject(Property property,
455b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            TypeEvaluator<V> evaluator, V... values) {
456b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        PropertyValuesHolder pvh = new PropertyValuesHolder(property);
457b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        pvh.setObjectValues(values);
458b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        pvh.setEvaluator(evaluator);
459b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        return pvh;
460b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    }
461b39f051631250c49936a475d0e64584afb7f1b93Chet Haase
462b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    /**
46316d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount     * Constructs and returns a PropertyValuesHolder with a given property and
46416d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount     * set of Object values. This variant also takes a TypeEvaluator because the system
46516d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount     * cannot automatically interpolate between objects of unknown type. This variant also
46616d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount     * takes a <code>TypeConverter</code> to convert from animated values to the type
46716d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount     * of the property. If only one value is supplied, the <code>TypeConverter</code>
46842516d19db936b10874c27e16eeacda041af01f9George Mount     * must be a {@link android.animation.BidirectionalTypeConverter} to retrieve the current
46916d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount     * value.
47016d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount     *
471fa21bdfd5a8a5da3ec0530f7cc884994f92dc597Chet Haase     * <p><strong>Note:</strong> The Object values are stored as references to the original
472fa21bdfd5a8a5da3ec0530f7cc884994f92dc597Chet Haase     * objects, which means that changes to those objects after this method is called will
473fa21bdfd5a8a5da3ec0530f7cc884994f92dc597Chet Haase     * affect the values on the PropertyValuesHolder. If the objects will be mutated externally
474fa21bdfd5a8a5da3ec0530f7cc884994f92dc597Chet Haase     * after this method is called, callers should pass a copy of those objects instead.
475fa21bdfd5a8a5da3ec0530f7cc884994f92dc597Chet Haase     *
47616d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount     * @param property The property being animated. Should not be null.
47716d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount     * @param converter Converts the animated object to the Property type.
47816d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount     * @param evaluator A TypeEvaluator that will be called on each animation frame to
47916d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount     * provide the necessary interpolation between the Object values to derive the animated
48016d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount     * value.
48116d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount     * @param values The values that the property will animate between.
48216d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
48316d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount     * @see #setConverter(TypeConverter)
48416d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount     * @see TypeConverter
48516d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount     */
486d98f4ba86c02714d94ec3b6f35345cb0b04f7778George Mount    @SafeVarargs
48716d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount    public static <T, V> PropertyValuesHolder ofObject(Property<?, V> property,
48816d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount            TypeConverter<T, V> converter, TypeEvaluator<T> evaluator, T... values) {
48916d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount        PropertyValuesHolder pvh = new PropertyValuesHolder(property);
49016d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount        pvh.setConverter(converter);
49116d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount        pvh.setObjectValues(values);
49216d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount        pvh.setEvaluator(evaluator);
49316d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount        return pvh;
49416d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount    }
49516d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount
49616d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount    /**
497c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * Constructs and returns a PropertyValuesHolder with a given property and
498c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * a Path along which the values should be animated. This variant supports a
499c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * <code>TypeConverter</code> to convert from <code>PointF</code> to the target
500c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * type.
501c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     *
502984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount     * <p>The PointF passed to <code>converter</code> or <code>property</code>, if
503984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount     * <code>converter</code> is <code>null</code>, is reused on each animation frame and should
504984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount     * not be stored by the setter or TypeConverter.</p>
505984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount     *
506c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * @param property The property being animated. Should not be null.
507c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * @param converter Converts a PointF to the type associated with the setter. May be
508c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     *                  null if conversion is unnecessary.
509c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * @param path The Path along which the values should be animated.
510c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
511c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     */
512c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount    public static <V> PropertyValuesHolder ofObject(Property<?, V> property,
513c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount            TypeConverter<PointF, V> converter, Path path) {
514984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        PropertyValuesHolder pvh = new PropertyValuesHolder(property);
515984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        pvh.mKeyframes = KeyframeSet.ofPath(path);
516984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        pvh.mValueType = PointF.class;
517c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount        pvh.setConverter(converter);
518c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount        return pvh;
519c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount    }
520c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount
521c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount    /**
5222794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * Constructs and returns a PropertyValuesHolder object with the specified property name and set
5232794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * of values. These values can be of any type, but the type should be consistent so that
524d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * an appropriate {@link android.animation.TypeEvaluator} can be found that matches
525d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * the common type.
526d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * <p>If there is only one value, it is assumed to be the end value of an animation,
527d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * and an initial value will be derived, if possible, by calling a getter function
528d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * on the object. Also, if any value is null, the value will be filled in when the animation
529d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * starts in the same way. This mechanism of automatically getting null values only works
530d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * if the PropertyValuesHolder object is used in conjunction
5311a8e404743a27da08d0f2df5480c51725c9b001aChet Haase     * {@link ObjectAnimator}, and with a getter function
5321a8e404743a27da08d0f2df5480c51725c9b001aChet Haase     * derived automatically from <code>propertyName</code>, since otherwise PropertyValuesHolder has
533d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * no way of determining what the value should be.
534d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param propertyName The name of the property associated with this set of values. This
535a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * can be the actual property name to be used when using a ObjectAnimator object, or
536d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * just a name used to get animated values, such as if this object is used with an
537a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * ValueAnimator object.
538d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param values The set of values to animate between.
539d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
5402794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    public static PropertyValuesHolder ofKeyframe(String propertyName, Keyframe... values) {
5417c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        KeyframeSet keyframeSet = KeyframeSet.ofKeyframe(values);
542984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        return ofKeyframes(propertyName, keyframeSet);
543d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
544d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
545d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
546b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * Constructs and returns a PropertyValuesHolder object with the specified property and set
547b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * of values. These values can be of any type, but the type should be consistent so that
548b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * an appropriate {@link android.animation.TypeEvaluator} can be found that matches
549b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * the common type.
550b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * <p>If there is only one value, it is assumed to be the end value of an animation,
551b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * and an initial value will be derived, if possible, by calling the property's
552b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * {@link android.util.Property#get(Object)} function.
553b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * Also, if any value is null, the value will be filled in when the animation
554b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * starts in the same way. This mechanism of automatically getting null values only works
555b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * if the PropertyValuesHolder object is used in conjunction with
556b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * {@link ObjectAnimator}, since otherwise PropertyValuesHolder has
557b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * no way of determining what the value should be.
558b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @param property The property associated with this set of values. Should not be null.
559b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @param values The set of values to animate between.
560b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     */
561b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    public static PropertyValuesHolder ofKeyframe(Property property, Keyframe... values) {
562b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        KeyframeSet keyframeSet = KeyframeSet.ofKeyframe(values);
563984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        return ofKeyframes(property, keyframeSet);
564984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount    }
565984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount
566984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount    static PropertyValuesHolder ofKeyframes(String propertyName, Keyframes keyframes) {
567984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        if (keyframes instanceof Keyframes.IntKeyframes) {
568984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            return new IntPropertyValuesHolder(propertyName, (Keyframes.IntKeyframes) keyframes);
569984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        } else if (keyframes instanceof Keyframes.FloatKeyframes) {
570984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            return new FloatPropertyValuesHolder(propertyName,
571984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                    (Keyframes.FloatKeyframes) keyframes);
572984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        } else {
573984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName);
574984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            pvh.mKeyframes = keyframes;
575984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            pvh.mValueType = keyframes.getType();
576984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            return pvh;
577b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        }
578984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount    }
579984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount
580984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount    static PropertyValuesHolder ofKeyframes(Property property, Keyframes keyframes) {
581984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        if (keyframes instanceof Keyframes.IntKeyframes) {
582984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            return new IntPropertyValuesHolder(property, (Keyframes.IntKeyframes) keyframes);
583984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        } else if (keyframes instanceof Keyframes.FloatKeyframes) {
584984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            return new FloatPropertyValuesHolder(property, (Keyframes.FloatKeyframes) keyframes);
585984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        } else {
586b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            PropertyValuesHolder pvh = new PropertyValuesHolder(property);
587984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            pvh.mKeyframes = keyframes;
588984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            pvh.mValueType = keyframes.getType();
589b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            return pvh;
590b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        }
591b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    }
592b39f051631250c49936a475d0e64584afb7f1b93Chet Haase
593b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    /**
5942794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * Set the animated values for this object to this set of ints.
595d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * If there is only one value, it is assumed to be the end value of an animation,
596d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * and an initial value will be derived, if possible, by calling a getter function
597d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * on the object. Also, if any value is null, the value will be filled in when the animation
598d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * starts in the same way. This mechanism of automatically getting null values only works
599d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * if the PropertyValuesHolder object is used in conjunction
6001a8e404743a27da08d0f2df5480c51725c9b001aChet Haase     * {@link ObjectAnimator}, and with a getter function
6011a8e404743a27da08d0f2df5480c51725c9b001aChet Haase     * derived automatically from <code>propertyName</code>, since otherwise PropertyValuesHolder has
602d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * no way of determining what the value should be.
6032794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     *
6042794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @param values One or more values that the animation will animate between.
6052794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     */
6062794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    public void setIntValues(int... values) {
6072794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase        mValueType = int.class;
608984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        mKeyframes = KeyframeSet.ofInt(values);
6092794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    }
6102794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase
6112794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    /**
6122794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * Set the animated values for this object to this set of floats.
6132794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * If there is only one value, it is assumed to be the end value of an animation,
6142794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * and an initial value will be derived, if possible, by calling a getter function
6152794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * on the object. Also, if any value is null, the value will be filled in when the animation
6162794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * starts in the same way. This mechanism of automatically getting null values only works
6172794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * if the PropertyValuesHolder object is used in conjunction
6181a8e404743a27da08d0f2df5480c51725c9b001aChet Haase     * {@link ObjectAnimator}, and with a getter function
6191a8e404743a27da08d0f2df5480c51725c9b001aChet Haase     * derived automatically from <code>propertyName</code>, since otherwise PropertyValuesHolder has
6202794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * no way of determining what the value should be.
6212794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     *
6222794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @param values One or more values that the animation will animate between.
6232794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     */
6242794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    public void setFloatValues(float... values) {
6252794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase        mValueType = float.class;
626984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        mKeyframes = KeyframeSet.ofFloat(values);
6272794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    }
6282794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase
6292794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    /**
6302794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * Set the animated values for this object to this set of Keyframes.
6312794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     *
6322794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @param values One or more values that the animation will animate between.
633d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
6342794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    public void setKeyframes(Keyframe... values) {
635d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        int numKeyframes = values.length;
636d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        Keyframe keyframes[] = new Keyframe[Math.max(numKeyframes,2)];
6372794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase        mValueType = ((Keyframe)values[0]).getType();
6382794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase        for (int i = 0; i < numKeyframes; ++i) {
6392794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase            keyframes[i] = (Keyframe)values[i];
640d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        }
641984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        mKeyframes = new KeyframeSet(keyframes);
642d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
643d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
6442794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    /**
6452794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * Set the animated values for this object to this set of Objects.
6462794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * If there is only one value, it is assumed to be the end value of an animation,
6472794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * and an initial value will be derived, if possible, by calling a getter function
6482794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * on the object. Also, if any value is null, the value will be filled in when the animation
6492794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * starts in the same way. This mechanism of automatically getting null values only works
6502794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * if the PropertyValuesHolder object is used in conjunction
6511a8e404743a27da08d0f2df5480c51725c9b001aChet Haase     * {@link ObjectAnimator}, and with a getter function
6521a8e404743a27da08d0f2df5480c51725c9b001aChet Haase     * derived automatically from <code>propertyName</code>, since otherwise PropertyValuesHolder has
6532794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * no way of determining what the value should be.
654fa21bdfd5a8a5da3ec0530f7cc884994f92dc597Chet Haase     *
655fa21bdfd5a8a5da3ec0530f7cc884994f92dc597Chet Haase     * <p><strong>Note:</strong> The Object values are stored as references to the original
656fa21bdfd5a8a5da3ec0530f7cc884994f92dc597Chet Haase     * objects, which means that changes to those objects after this method is called will
657fa21bdfd5a8a5da3ec0530f7cc884994f92dc597Chet Haase     * affect the values on the PropertyValuesHolder. If the objects will be mutated externally
658fa21bdfd5a8a5da3ec0530f7cc884994f92dc597Chet Haase     * after this method is called, callers should pass a copy of those objects instead.
659fa21bdfd5a8a5da3ec0530f7cc884994f92dc597Chet Haase     *
6602794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @param values One or more values that the animation will animate between.
6612794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     */
6622794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    public void setObjectValues(Object... values) {
6632794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase        mValueType = values[0].getClass();
664984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        mKeyframes = KeyframeSet.ofObject(values);
6654ae3e6af08919e31174e049d2509e73a9bebb2b3Chet Haase        if (mEvaluator != null) {
666984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            mKeyframes.setEvaluator(mEvaluator);
6674ae3e6af08919e31174e049d2509e73a9bebb2b3Chet Haase        }
6682794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    }
669d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
670d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
67116d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount     * Sets the converter to convert from the values type to the setter's parameter type.
67242516d19db936b10874c27e16eeacda041af01f9George Mount     * If only one value is supplied, <var>converter</var> must be a
67342516d19db936b10874c27e16eeacda041af01f9George Mount     * {@link android.animation.BidirectionalTypeConverter}.
67416d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount     * @param converter The converter to use to convert values.
67516d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount     */
67616d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount    public void setConverter(TypeConverter converter) {
67716d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount        mConverter = converter;
67816d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount    }
67916d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount
68016d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount    /**
681d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * Determine the setter or getter function using the JavaBeans convention of setFoo or
682d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * getFoo for a property named 'foo'. This function figures out what the name of the
683d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * function should be and uses reflection to find the Method with that name on the
684d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * target object.
685d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     *
686d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param targetClass The class to search for the method
687d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param prefix "set" or "get", depending on whether we need a setter or getter.
688d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param valueType The type of the parameter (in the case of a setter). This type
689d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * is derived from the values set on this PropertyValuesHolder. This type is used as
690d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * a first guess at the parameter type, but we check for methods with several different
691d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * types to avoid problems with slight mis-matches between supplied values and actual
692d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * value types used on the setter.
693d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @return Method the method associated with mPropertyName.
694d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
695d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    private Method getPropertyFunction(Class targetClass, String prefix, Class valueType) {
696d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        // TODO: faster implementation...
697d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        Method returnVal = null;
6986e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase        String methodName = getMethodName(prefix, mPropertyName);
699d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        Class args[] = null;
700d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        if (valueType == null) {
701d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            try {
702d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                returnVal = targetClass.getMethod(methodName, args);
703d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            } catch (NoSuchMethodException e) {
704db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase                // Swallow the error, log it later
705d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            }
706d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        } else {
707d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            args = new Class[1];
708d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            Class typeVariants[];
70916d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount            if (valueType.equals(Float.class)) {
710d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                typeVariants = FLOAT_VARIANTS;
71116d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount            } else if (valueType.equals(Integer.class)) {
712d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                typeVariants = INTEGER_VARIANTS;
71316d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount            } else if (valueType.equals(Double.class)) {
714d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                typeVariants = DOUBLE_VARIANTS;
715d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            } else {
716d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                typeVariants = new Class[1];
71716d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount                typeVariants[0] = valueType;
718d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            }
719d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            for (Class typeVariant : typeVariants) {
720d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                args[0] = typeVariant;
721d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                try {
722d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                    returnVal = targetClass.getMethod(methodName, args);
72316d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount                    if (mConverter == null) {
72416d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount                        // change the value type to suit
72516d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount                        mValueType = typeVariant;
72616d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount                    }
727d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                    return returnVal;
728d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                } catch (NoSuchMethodException e) {
729d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                    // Swallow the error and keep trying other variants
730d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                }
731d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            }
732602e4d3824bf8b9cb9f817375d195b969712176aChet Haase            // If we got here, then no appropriate function was found
733db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase        }
734db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase
735db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase        if (returnVal == null) {
736db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase            Log.w("PropertyValuesHolder", "Method " +
73716d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount                    getMethodName(prefix, mPropertyName) + "() with type " + valueType +
738db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase                    " not found on target class " + targetClass);
739d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        }
740602e4d3824bf8b9cb9f817375d195b969712176aChet Haase
741d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        return returnVal;
742d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
743d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
744d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
745d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
746d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * Returns the setter or getter requested. This utility function checks whether the
747d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * requested method exists in the propertyMapMap cache. If not, it calls another
748d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * utility function to request the Method from the targetClass directly.
749d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param targetClass The Class on which the requested method should exist.
750d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param propertyMapMap The cache of setters/getters derived so far.
751d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param prefix "set" or "get", for the setter or getter.
752d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param valueType The type of parameter passed into the method (null for getter).
753d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @return Method the method associated with mPropertyName.
754d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
755d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    private Method setupSetterOrGetter(Class targetClass,
756d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            HashMap<Class, HashMap<String, Method>> propertyMapMap,
757d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            String prefix, Class valueType) {
758d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        Method setterOrGetter = null;
759691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount        synchronized(propertyMapMap) {
760d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            // Have to lock property map prior to reading it, to guard against
761d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            // another thread putting something in there after we've checked it
762d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            // but before we've added an entry to it
763d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            HashMap<String, Method> propertyMap = propertyMapMap.get(targetClass);
764691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount            boolean wasInMap = false;
765d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            if (propertyMap != null) {
766691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                wasInMap = propertyMap.containsKey(mPropertyName);
767691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                if (wasInMap) {
768691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    setterOrGetter = propertyMap.get(mPropertyName);
769691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                }
770d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            }
771691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount            if (!wasInMap) {
772d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                setterOrGetter = getPropertyFunction(targetClass, prefix, valueType);
773d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                if (propertyMap == null) {
774d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                    propertyMap = new HashMap<String, Method>();
775d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                    propertyMapMap.put(targetClass, propertyMap);
776d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                }
777d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                propertyMap.put(mPropertyName, setterOrGetter);
778d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            }
779d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        }
780d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        return setterOrGetter;
781d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
782d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
783d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
784d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * Utility function to get the setter from targetClass
785d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param targetClass The Class on which the requested method should exist.
786d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
7876e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase    void setupSetter(Class targetClass) {
78816d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount        Class<?> propertyType = mConverter == null ? mValueType : mConverter.getTargetType();
78916d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount        mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", propertyType);
790d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
791d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
792d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
793d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * Utility function to get the getter from targetClass
794d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
795d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    private void setupGetter(Class targetClass) {
796d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        mGetter = setupSetterOrGetter(targetClass, sGetterPropertyMap, "get", null);
797d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
798d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
799d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
800a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Internal function (called from ObjectAnimator) to set up the setter and getter
801d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * prior to running the animation. If the setter has not been manually set for this
802d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * object, it will be derived automatically given the property name, target object, and
803d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * types of values supplied. If no getter has been set, it will be supplied iff any of the
804d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * supplied values was null. If there is a null value, then the getter (supplied or derived)
805d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * will be called to set those null values to the current value of the property
806d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * on the target object.
807d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param target The object on which the setter (and possibly getter) exist.
808d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
809d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    void setupSetterAndGetter(Object target) {
810b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        if (mProperty != null) {
811b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            // check to make sure that mProperty is on the class of target
812b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            try {
81316d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount                Object testValue = null;
814d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                List<Keyframe> keyframes = mKeyframes.getKeyframes();
815984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                int keyframeCount = keyframes == null ? 0 : keyframes.size();
816984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                for (int i = 0; i < keyframeCount; i++) {
817984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                    Keyframe kf = keyframes.get(i);
8188619f48fb353740f7fd3f6eaa86fe493377e6cadYigit Boyar                    if (!kf.hasValue() || kf.valueWasSetOnStart()) {
81916d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount                        if (testValue == null) {
82016d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount                            testValue = convertBack(mProperty.get(target));
82116d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount                        }
82216d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount                        kf.setValue(testValue);
8238619f48fb353740f7fd3f6eaa86fe493377e6cadYigit Boyar                        kf.setValueWasSetOnStart(true);
824b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                    }
825b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                }
826b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                return;
827b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            } catch (ClassCastException e) {
828db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase                Log.w("PropertyValuesHolder","No such property (" + mProperty.getName() +
829b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                        ") on target object " + target + ". Trying reflection instead");
830b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                mProperty = null;
831b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            }
832b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        }
833691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount        // We can't just say 'else' here because the catch statement sets mProperty to null.
834691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount        if (mProperty == null) {
835691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount            Class targetClass = target.getClass();
836691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount            if (mSetter == null) {
837691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                setupSetter(targetClass);
838691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount            }
839691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount            List<Keyframe> keyframes = mKeyframes.getKeyframes();
840691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount            int keyframeCount = keyframes == null ? 0 : keyframes.size();
841691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount            for (int i = 0; i < keyframeCount; i++) {
842691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                Keyframe kf = keyframes.get(i);
843691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                if (!kf.hasValue() || kf.valueWasSetOnStart()) {
844db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase                    if (mGetter == null) {
845691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        setupGetter(targetClass);
846691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        if (mGetter == null) {
847691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                            // Already logged the error - just return to avoid NPE
848691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                            return;
849691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        }
850691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    }
851691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    try {
852691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        Object value = convertBack(mGetter.invoke(target));
853691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        kf.setValue(value);
854691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        kf.setValueWasSetOnStart(true);
855691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    } catch (InvocationTargetException e) {
856691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        Log.e("PropertyValuesHolder", e.toString());
857691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    } catch (IllegalAccessException e) {
858691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        Log.e("PropertyValuesHolder", e.toString());
859db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase                    }
860d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                }
861d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            }
862d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        }
863d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
864d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
86516d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount    private Object convertBack(Object value) {
86616d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount        if (mConverter != null) {
86742516d19db936b10874c27e16eeacda041af01f9George Mount            if (!(mConverter instanceof BidirectionalTypeConverter)) {
86816d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount                throw new IllegalArgumentException("Converter "
86916d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount                        + mConverter.getClass().getName()
87042516d19db936b10874c27e16eeacda041af01f9George Mount                        + " must be a BidirectionalTypeConverter");
87116d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount            }
87242516d19db936b10874c27e16eeacda041af01f9George Mount            value = ((BidirectionalTypeConverter) mConverter).convertBack(value);
87316d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount        }
87416d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount        return value;
87516d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount    }
87616d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount
877d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
87821cd1389d2ef218b20994b617c57af120841a57fChet Haase     * Utility function to set the value stored in a particular Keyframe. The value used is
87921cd1389d2ef218b20994b617c57af120841a57fChet Haase     * whatever the value is for the property name specified in the keyframe on the target object.
88021cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
88121cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param target The target object from which the current value should be extracted.
88221cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param kf The keyframe which holds the property name and value.
88321cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
88421cd1389d2ef218b20994b617c57af120841a57fChet Haase    private void setupValue(Object target, Keyframe kf) {
885b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        if (mProperty != null) {
88616d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount            Object value = convertBack(mProperty.get(target));
88716d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount            kf.setValue(value);
888406a02b59d3a8f9890509200f048c23c3b3200b7Chet Haase        } else {
889406a02b59d3a8f9890509200f048c23c3b3200b7Chet Haase            try {
890db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase                if (mGetter == null) {
891406a02b59d3a8f9890509200f048c23c3b3200b7Chet Haase                    Class targetClass = target.getClass();
892406a02b59d3a8f9890509200f048c23c3b3200b7Chet Haase                    setupGetter(targetClass);
893406a02b59d3a8f9890509200f048c23c3b3200b7Chet Haase                    if (mGetter == null) {
894406a02b59d3a8f9890509200f048c23c3b3200b7Chet Haase                        // Already logged the error - just return to avoid NPE
895406a02b59d3a8f9890509200f048c23c3b3200b7Chet Haase                        return;
896406a02b59d3a8f9890509200f048c23c3b3200b7Chet Haase                    }
897db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase                }
898406a02b59d3a8f9890509200f048c23c3b3200b7Chet Haase                Object value = convertBack(mGetter.invoke(target));
899406a02b59d3a8f9890509200f048c23c3b3200b7Chet Haase                kf.setValue(value);
900406a02b59d3a8f9890509200f048c23c3b3200b7Chet Haase            } catch (InvocationTargetException e) {
901406a02b59d3a8f9890509200f048c23c3b3200b7Chet Haase                Log.e("PropertyValuesHolder", e.toString());
902406a02b59d3a8f9890509200f048c23c3b3200b7Chet Haase            } catch (IllegalAccessException e) {
903406a02b59d3a8f9890509200f048c23c3b3200b7Chet Haase                Log.e("PropertyValuesHolder", e.toString());
90421cd1389d2ef218b20994b617c57af120841a57fChet Haase            }
90521cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
90621cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
90721cd1389d2ef218b20994b617c57af120841a57fChet Haase
90821cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
909a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * This function is called by ObjectAnimator when setting the start values for an animation.
91021cd1389d2ef218b20994b617c57af120841a57fChet Haase     * The start values are set according to the current values in the target object. The
91121cd1389d2ef218b20994b617c57af120841a57fChet Haase     * property whose value is extracted is whatever is specified by the propertyName of this
91221cd1389d2ef218b20994b617c57af120841a57fChet Haase     * PropertyValuesHolder object.
91321cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
91421cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param target The object which holds the start values that should be set.
91521cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
91621cd1389d2ef218b20994b617c57af120841a57fChet Haase    void setupStartValue(Object target) {
917d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        List<Keyframe> keyframes = mKeyframes.getKeyframes();
918984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        if (!keyframes.isEmpty()) {
919984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            setupValue(target, keyframes.get(0));
920984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        }
92121cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
92221cd1389d2ef218b20994b617c57af120841a57fChet Haase
92321cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
924a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * This function is called by ObjectAnimator when setting the end values for an animation.
92521cd1389d2ef218b20994b617c57af120841a57fChet Haase     * The end values are set according to the current values in the target object. The
92621cd1389d2ef218b20994b617c57af120841a57fChet Haase     * property whose value is extracted is whatever is specified by the propertyName of this
92721cd1389d2ef218b20994b617c57af120841a57fChet Haase     * PropertyValuesHolder object.
92821cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
92921cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param target The object which holds the start values that should be set.
93021cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
93121cd1389d2ef218b20994b617c57af120841a57fChet Haase    void setupEndValue(Object target) {
932d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        List<Keyframe> keyframes = mKeyframes.getKeyframes();
933984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        if (!keyframes.isEmpty()) {
934984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            setupValue(target, keyframes.get(keyframes.size() - 1));
935984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        }
93621cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
93721cd1389d2ef218b20994b617c57af120841a57fChet Haase
93821cd1389d2ef218b20994b617c57af120841a57fChet Haase    @Override
93921cd1389d2ef218b20994b617c57af120841a57fChet Haase    public PropertyValuesHolder clone() {
9407c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        try {
9417c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            PropertyValuesHolder newPVH = (PropertyValuesHolder) super.clone();
9427c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            newPVH.mPropertyName = mPropertyName;
943b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            newPVH.mProperty = mProperty;
944984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            newPVH.mKeyframes = mKeyframes.clone();
9457c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            newPVH.mEvaluator = mEvaluator;
9467c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            return newPVH;
9477c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        } catch (CloneNotSupportedException e) {
9487c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            // won't reach here
9497c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            return null;
95021cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
95121cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
9527c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
95321cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
954d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * Internal function to set the value on the target object, using the setter set up
955a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * earlier on this PropertyValuesHolder object. This function is called by ObjectAnimator
956a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * to handle turning the value calculated by ValueAnimator into a value set on the object
957d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * according to the name of the property.
958d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param target The target object on which the value is set
959d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
960d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    void setAnimatedValue(Object target) {
961b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        if (mProperty != null) {
962b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            mProperty.set(target, getAnimatedValue());
963b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        }
964d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        if (mSetter != null) {
965d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            try {
9667c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                mTmpValueArray[0] = getAnimatedValue();
967d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                mSetter.invoke(target, mTmpValueArray);
968d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            } catch (InvocationTargetException e) {
969d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                Log.e("PropertyValuesHolder", e.toString());
970d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            } catch (IllegalAccessException e) {
971d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                Log.e("PropertyValuesHolder", e.toString());
972d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            }
973d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        }
974d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
975d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
976d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
977a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Internal function, called by ValueAnimator, to set up the TypeEvaluator that will be used
978d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * to calculate animated values.
979d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
980d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    void init() {
981d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        if (mEvaluator == null) {
982b2ab04ffb6894f399d5c9ceb15f64eb17b654426Chet Haase            // We already handle int and float automatically, but not their Object
9837c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            // equivalents
9847c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            mEvaluator = (mValueType == Integer.class) ? sIntEvaluator :
9857c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    (mValueType == Float.class) ? sFloatEvaluator :
9867c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    null;
9877c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
9887c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        if (mEvaluator != null) {
9897c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            // KeyframeSet knows how to evaluate the common types - only give it a custom
990b2ab04ffb6894f399d5c9ceb15f64eb17b654426Chet Haase            // evaluator if one has been set on this class
991984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            mKeyframes.setEvaluator(mEvaluator);
992d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        }
993d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
994d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
995d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
996d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * The TypeEvaluator will be automatically determined based on the type of values
997d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * supplied to PropertyValuesHolder. The evaluator can be manually set, however, if so
998d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * desired. This may be important in cases where either the type of the values supplied
999d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * do not match the way that they should be interpolated between, or if the values
1000d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * are of a custom type or one not currently understood by the animation system. Currently,
1001b2ab04ffb6894f399d5c9ceb15f64eb17b654426Chet Haase     * only values of type float and int (and their Object equivalents: Float
1002d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * and Integer) are  correctly interpolated; all other types require setting a TypeEvaluator.
1003d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param evaluator
1004d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
10057c608f25d494c8a0a671e7373efbb47ca635367eChet Haase    public void setEvaluator(TypeEvaluator evaluator) {
1006d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        mEvaluator = evaluator;
1007984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        mKeyframes.setEvaluator(evaluator);
1008d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
1009d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
1010d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
1011d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * Function used to calculate the value according to the evaluator set up for
1012a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * this PropertyValuesHolder object. This function is called by ValueAnimator.animateValue().
1013d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     *
1014d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param fraction The elapsed, interpolated fraction of the animation.
1015d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
10167c608f25d494c8a0a671e7373efbb47ca635367eChet Haase    void calculateValue(float fraction) {
1017984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        Object value = mKeyframes.getValue(fraction);
101816d2c9cc6bd67131d9921fbc14a69d88f48f48caGeorge Mount        mAnimatedValue = mConverter == null ? value : mConverter.convert(value);
1019d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
1020d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
1021d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
1022d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * Sets the name of the property that will be animated. This name is used to derive
1023d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * a setter function that will be called to set animated values.
1024d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * For example, a property name of <code>foo</code> will result
1025d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * in a call to the function <code>setFoo()</code> on the target object. If either
1026d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will
1027d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * also be derived and called.
1028d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     *
1029d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * <p>Note that the setter function derived from this property name
1030d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * must take the same parameter type as the
1031d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * <code>valueFrom</code> and <code>valueTo</code> properties, otherwise the call to
1032d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * the setter function will fail.</p>
1033d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     *
1034d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param propertyName The name of the property being animated.
1035d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
1036d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    public void setPropertyName(String propertyName) {
1037d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        mPropertyName = propertyName;
1038d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
1039d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
1040d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
1041b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * Sets the property that will be animated.
1042b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     *
1043b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * <p>Note that if this PropertyValuesHolder object is used with ObjectAnimator, the property
1044b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * must exist on the target object specified in that ObjectAnimator.</p>
1045b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     *
1046b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @param property The property being animated.
1047b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     */
1048b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    public void setProperty(Property property) {
1049b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        mProperty = property;
1050b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    }
1051b39f051631250c49936a475d0e64584afb7f1b93Chet Haase
1052b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    /**
1053d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * Gets the name of the property that will be animated. This name will be used to derive
1054d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * a setter function that will be called to set animated values.
1055d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * For example, a property name of <code>foo</code> will result
1056d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * in a call to the function <code>setFoo()</code> on the target object. If either
1057d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will
1058d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * also be derived and called.
1059d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
1060d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    public String getPropertyName() {
1061d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        return mPropertyName;
1062d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
1063d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
1064d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
1065a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Internal function, called by ValueAnimator and ObjectAnimator, to retrieve the value
1066d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * most recently calculated in calculateValue().
1067d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @return
1068d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
1069d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    Object getAnimatedValue() {
1070d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        return mAnimatedValue;
1071d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
10727c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
1073766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu    /**
1074766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu     * PropertyValuesHolder is Animators use to hold internal animation related data.
1075766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu     * Therefore, in order to replicate the animation behavior, we need to get data out of
1076766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu     * PropertyValuesHolder.
1077766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu     * @hide
1078766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu     */
1079766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu    public void getPropertyValues(PropertyValues values) {
1080766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu        init();
1081766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu        values.propertyName = mPropertyName;
1082766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu        values.type = mValueType;
1083766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu        values.startValue = mKeyframes.getValue(0);
1084766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu        if (values.startValue instanceof PathParser.PathData) {
1085766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu            // PathData evaluator returns the same mutable PathData object when query fraction,
1086766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu            // so we have to make a copy here.
1087766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu            values.startValue = new PathParser.PathData((PathParser.PathData) values.startValue);
1088766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu        }
1089766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu        values.endValue = mKeyframes.getValue(1);
1090766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu        if (values.endValue instanceof PathParser.PathData) {
1091766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu            // PathData evaluator returns the same mutable PathData object when query fraction,
1092766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu            // so we have to make a copy here.
1093766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu            values.endValue = new PathParser.PathData((PathParser.PathData) values.endValue);
1094766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu        }
1095766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu        // TODO: We need a better way to get data out of keyframes.
1096766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu        if (mKeyframes instanceof PathKeyframes.FloatKeyframesBase
1097a6b967cfc54408f6ee78ae0e4695eca6efd62e89Doris Liu                || mKeyframes instanceof PathKeyframes.IntKeyframesBase
1098a6b967cfc54408f6ee78ae0e4695eca6efd62e89Doris Liu                || (mKeyframes.getKeyframes() != null && mKeyframes.getKeyframes().size() > 2)) {
1099a6b967cfc54408f6ee78ae0e4695eca6efd62e89Doris Liu            // When a pvh has more than 2 keyframes, that means there are intermediate values in
1100a6b967cfc54408f6ee78ae0e4695eca6efd62e89Doris Liu            // addition to start/end values defined for animators. Another case where such
1101a6b967cfc54408f6ee78ae0e4695eca6efd62e89Doris Liu            // intermediate values are defined is when animator has a path to animate along. In
1102a6b967cfc54408f6ee78ae0e4695eca6efd62e89Doris Liu            // these cases, a data source is needed to capture these intermediate values.
1103766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu            values.dataSource = new PropertyValues.DataSource() {
1104766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu                @Override
1105766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu                public Object getValueAtFraction(float fraction) {
1106766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu                    return mKeyframes.getValue(fraction);
1107766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu                }
1108766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu            };
1109766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu        } else {
1110766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu            values.dataSource = null;
1111766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu        }
1112766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu    }
1113766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu
111494db09917a17976135e2c63d8e4171c54730c079Doris Liu    /**
111594db09917a17976135e2c63d8e4171c54730c079Doris Liu     * @hide
111694db09917a17976135e2c63d8e4171c54730c079Doris Liu     */
111794db09917a17976135e2c63d8e4171c54730c079Doris Liu    public Class getValueType() {
111894db09917a17976135e2c63d8e4171c54730c079Doris Liu        return mValueType;
111994db09917a17976135e2c63d8e4171c54730c079Doris Liu    }
112094db09917a17976135e2c63d8e4171c54730c079Doris Liu
1121e9140a72b1059574046a624b471b2c3a35806496Chet Haase    @Override
1122e9140a72b1059574046a624b471b2c3a35806496Chet Haase    public String toString() {
1123984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        return mPropertyName + ": " + mKeyframes.toString();
1124e9140a72b1059574046a624b471b2c3a35806496Chet Haase    }
1125e9140a72b1059574046a624b471b2c3a35806496Chet Haase
11266e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase    /**
11276e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase     * Utility method to derive a setter/getter method name from a property name, where the
11286e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase     * prefix is typically "set" or "get" and the first letter of the property name is
11296e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase     * capitalized.
11306e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase     *
11316e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase     * @param prefix The precursor to the method name, before the property name begins, typically
11326e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase     * "set" or "get".
11336e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase     * @param propertyName The name of the property that represents the bulk of the method name
11346e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase     * after the prefix. The first letter of this word will be capitalized in the resulting
11356e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase     * method name.
11366e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase     * @return String the property name converted to a method name according to the conventions
11376e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase     * specified above.
11386e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase     */
11396e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase    static String getMethodName(String prefix, String propertyName) {
1140b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        if (propertyName == null || propertyName.length() == 0) {
1141b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            // shouldn't get here
1142b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            return prefix;
1143b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        }
1144b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        char firstLetter = Character.toUpperCase(propertyName.charAt(0));
11456e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase        String theRest = propertyName.substring(1);
11466e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase        return prefix + firstLetter + theRest;
11476e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase    }
11486e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase
11497c608f25d494c8a0a671e7373efbb47ca635367eChet Haase    static class IntPropertyValuesHolder extends PropertyValuesHolder {
11507c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
1151b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        // Cache JNI functions to avoid looking them up twice
1152fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat        private static final HashMap<Class, HashMap<String, Long>> sJNISetterPropertyMap =
1153fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat                new HashMap<Class, HashMap<String, Long>>();
1154fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat        long mJniSetter;
1155b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        private IntProperty mIntProperty;
11566e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase
1157984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        Keyframes.IntKeyframes mIntKeyframes;
11587c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        int mIntAnimatedValue;
11597c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
1160984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        public IntPropertyValuesHolder(String propertyName, Keyframes.IntKeyframes keyframes) {
11617c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            super(propertyName);
11627c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            mValueType = int.class;
1163984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            mKeyframes = keyframes;
1164984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            mIntKeyframes = keyframes;
11657c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
11667c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
1167984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        public IntPropertyValuesHolder(Property property, Keyframes.IntKeyframes keyframes) {
1168b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            super(property);
1169b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            mValueType = int.class;
1170984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            mKeyframes = keyframes;
1171984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            mIntKeyframes = keyframes;
1172b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            if (property instanceof  IntProperty) {
1173b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                mIntProperty = (IntProperty) mProperty;
1174b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            }
1175b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        }
1176b39f051631250c49936a475d0e64584afb7f1b93Chet Haase
11777c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        public IntPropertyValuesHolder(String propertyName, int... values) {
11787c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            super(propertyName);
11797c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            setIntValues(values);
1180691ac26817d489d9770aa6ba7b098ff17e8be99aChet Haase        }
1181691ac26817d489d9770aa6ba7b098ff17e8be99aChet Haase
1182b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        public IntPropertyValuesHolder(Property property, int... values) {
1183b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            super(property);
1184b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            setIntValues(values);
1185b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            if (property instanceof  IntProperty) {
1186b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                mIntProperty = (IntProperty) mProperty;
1187b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            }
1188b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        }
1189b39f051631250c49936a475d0e64584afb7f1b93Chet Haase
1190691ac26817d489d9770aa6ba7b098ff17e8be99aChet Haase        @Override
11919f3b31b9530a2121b4557fc312972c4faa133d5eDoris Liu        public void setProperty(Property property) {
11929f3b31b9530a2121b4557fc312972c4faa133d5eDoris Liu            if (property instanceof IntProperty) {
11939f3b31b9530a2121b4557fc312972c4faa133d5eDoris Liu                mIntProperty = (IntProperty) property;
11949f3b31b9530a2121b4557fc312972c4faa133d5eDoris Liu            } else {
11959f3b31b9530a2121b4557fc312972c4faa133d5eDoris Liu                super.setProperty(property);
11969f3b31b9530a2121b4557fc312972c4faa133d5eDoris Liu            }
11979f3b31b9530a2121b4557fc312972c4faa133d5eDoris Liu        }
11989f3b31b9530a2121b4557fc312972c4faa133d5eDoris Liu
11999f3b31b9530a2121b4557fc312972c4faa133d5eDoris Liu        @Override
1200691ac26817d489d9770aa6ba7b098ff17e8be99aChet Haase        public void setIntValues(int... values) {
1201691ac26817d489d9770aa6ba7b098ff17e8be99aChet Haase            super.setIntValues(values);
1202984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            mIntKeyframes = (Keyframes.IntKeyframes) mKeyframes;
12037c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
12047c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
12057c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        @Override
12067c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        void calculateValue(float fraction) {
1207984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            mIntAnimatedValue = mIntKeyframes.getIntValue(fraction);
12087c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
12097c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
12107c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        @Override
12117c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        Object getAnimatedValue() {
12127c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            return mIntAnimatedValue;
12137c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
12147c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
12157c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        @Override
12167c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        public IntPropertyValuesHolder clone() {
12177c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            IntPropertyValuesHolder newPVH = (IntPropertyValuesHolder) super.clone();
1218984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            newPVH.mIntKeyframes = (Keyframes.IntKeyframes) newPVH.mKeyframes;
12197c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            return newPVH;
12207c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
12217c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
12227c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        /**
12237c608f25d494c8a0a671e7373efbb47ca635367eChet Haase         * Internal function to set the value on the target object, using the setter set up
12247c608f25d494c8a0a671e7373efbb47ca635367eChet Haase         * earlier on this PropertyValuesHolder object. This function is called by ObjectAnimator
12257c608f25d494c8a0a671e7373efbb47ca635367eChet Haase         * to handle turning the value calculated by ValueAnimator into a value set on the object
12267c608f25d494c8a0a671e7373efbb47ca635367eChet Haase         * according to the name of the property.
12277c608f25d494c8a0a671e7373efbb47ca635367eChet Haase         * @param target The target object on which the value is set
12287c608f25d494c8a0a671e7373efbb47ca635367eChet Haase         */
12297c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        @Override
12307c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        void setAnimatedValue(Object target) {
1231b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            if (mIntProperty != null) {
1232b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                mIntProperty.setValue(target, mIntAnimatedValue);
1233b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                return;
1234b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            }
1235b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            if (mProperty != null) {
1236b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                mProperty.set(target, mIntAnimatedValue);
1237b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                return;
1238b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            }
12396e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            if (mJniSetter != 0) {
12406e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                nCallIntMethod(target, mJniSetter, mIntAnimatedValue);
12416e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                return;
12426e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            }
12437c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            if (mSetter != null) {
12447c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                try {
12457c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    mTmpValueArray[0] = mIntAnimatedValue;
12467c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    mSetter.invoke(target, mTmpValueArray);
12477c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                } catch (InvocationTargetException e) {
12487c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    Log.e("PropertyValuesHolder", e.toString());
12497c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                } catch (IllegalAccessException e) {
12507c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    Log.e("PropertyValuesHolder", e.toString());
12517c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                }
12527c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            }
12537c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
12546e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase
12556e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase        @Override
12566e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase        void setupSetter(Class targetClass) {
1257b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            if (mProperty != null) {
1258b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                return;
1259b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            }
12606e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            // Check new static hashmap<propName, int> for setter method
1261691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount            synchronized(sJNISetterPropertyMap) {
1262fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat                HashMap<String, Long> propertyMap = sJNISetterPropertyMap.get(targetClass);
1263691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                boolean wasInMap = false;
12646e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                if (propertyMap != null) {
1265691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    wasInMap = propertyMap.containsKey(mPropertyName);
1266691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    if (wasInMap) {
1267691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        Long jniSetter = propertyMap.get(mPropertyName);
1268691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        if (jniSetter != null) {
1269691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                            mJniSetter = jniSetter;
1270691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        }
12716e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                    }
12726e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                }
1273691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                if (!wasInMap) {
12746e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                    String methodName = getMethodName("set", mPropertyName);
1275691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    try {
1276691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        mJniSetter = nGetIntMethod(targetClass, methodName);
1277691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    } catch (NoSuchMethodError e) {
1278691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        // Couldn't find it via JNI - try reflection next. Probably means the method
1279691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        // doesn't exist, or the type is wrong. An error will be logged later if
1280691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        // reflection fails as well.
12816e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                    }
1282691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    if (propertyMap == null) {
1283691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        propertyMap = new HashMap<String, Long>();
1284691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        sJNISetterPropertyMap.put(targetClass, propertyMap);
1285691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    }
1286691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    propertyMap.put(mPropertyName, mJniSetter);
12876e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                }
12886e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            }
12896e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            if (mJniSetter == 0) {
12906e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                // Couldn't find method through fast JNI approach - just use reflection
12916e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                super.setupSetter(targetClass);
12926e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            }
12936e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase        }
12947c608f25d494c8a0a671e7373efbb47ca635367eChet Haase    }
12957c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
12967c608f25d494c8a0a671e7373efbb47ca635367eChet Haase    static class FloatPropertyValuesHolder extends PropertyValuesHolder {
12977c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
1298b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        // Cache JNI functions to avoid looking them up twice
1299fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat        private static final HashMap<Class, HashMap<String, Long>> sJNISetterPropertyMap =
1300fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat                new HashMap<Class, HashMap<String, Long>>();
1301fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat        long mJniSetter;
1302b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        private FloatProperty mFloatProperty;
13036e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase
1304984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        Keyframes.FloatKeyframes mFloatKeyframes;
13057c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        float mFloatAnimatedValue;
13067c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
1307984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        public FloatPropertyValuesHolder(String propertyName, Keyframes.FloatKeyframes keyframes) {
13087c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            super(propertyName);
13097c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            mValueType = float.class;
1310984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            mKeyframes = keyframes;
1311984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            mFloatKeyframes = keyframes;
13127c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
13137c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
1314984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount        public FloatPropertyValuesHolder(Property property, Keyframes.FloatKeyframes keyframes) {
1315b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            super(property);
1316b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            mValueType = float.class;
1317984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            mKeyframes = keyframes;
1318984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            mFloatKeyframes = keyframes;
1319b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            if (property instanceof FloatProperty) {
1320b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                mFloatProperty = (FloatProperty) mProperty;
1321b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            }
1322b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        }
1323b39f051631250c49936a475d0e64584afb7f1b93Chet Haase
13247c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        public FloatPropertyValuesHolder(String propertyName, float... values) {
13257c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            super(propertyName);
13267c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            setFloatValues(values);
1327691ac26817d489d9770aa6ba7b098ff17e8be99aChet Haase        }
1328691ac26817d489d9770aa6ba7b098ff17e8be99aChet Haase
1329b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        public FloatPropertyValuesHolder(Property property, float... values) {
1330b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            super(property);
1331b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            setFloatValues(values);
1332b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            if (property instanceof  FloatProperty) {
1333b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                mFloatProperty = (FloatProperty) mProperty;
1334b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            }
1335b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        }
1336b39f051631250c49936a475d0e64584afb7f1b93Chet Haase
1337691ac26817d489d9770aa6ba7b098ff17e8be99aChet Haase        @Override
13389f3b31b9530a2121b4557fc312972c4faa133d5eDoris Liu        public void setProperty(Property property) {
13399f3b31b9530a2121b4557fc312972c4faa133d5eDoris Liu            if (property instanceof FloatProperty) {
13409f3b31b9530a2121b4557fc312972c4faa133d5eDoris Liu                mFloatProperty = (FloatProperty) property;
13419f3b31b9530a2121b4557fc312972c4faa133d5eDoris Liu            } else {
13429f3b31b9530a2121b4557fc312972c4faa133d5eDoris Liu                super.setProperty(property);
13439f3b31b9530a2121b4557fc312972c4faa133d5eDoris Liu            }
13449f3b31b9530a2121b4557fc312972c4faa133d5eDoris Liu        }
13459f3b31b9530a2121b4557fc312972c4faa133d5eDoris Liu
13469f3b31b9530a2121b4557fc312972c4faa133d5eDoris Liu        @Override
1347691ac26817d489d9770aa6ba7b098ff17e8be99aChet Haase        public void setFloatValues(float... values) {
1348691ac26817d489d9770aa6ba7b098ff17e8be99aChet Haase            super.setFloatValues(values);
1349984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            mFloatKeyframes = (Keyframes.FloatKeyframes) mKeyframes;
13507c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
13517c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
13527c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        @Override
13537c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        void calculateValue(float fraction) {
1354984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            mFloatAnimatedValue = mFloatKeyframes.getFloatValue(fraction);
13557c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
13567c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
13577c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        @Override
13587c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        Object getAnimatedValue() {
13597c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            return mFloatAnimatedValue;
13607c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
13617c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
13627c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        @Override
13637c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        public FloatPropertyValuesHolder clone() {
13647c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            FloatPropertyValuesHolder newPVH = (FloatPropertyValuesHolder) super.clone();
1365984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            newPVH.mFloatKeyframes = (Keyframes.FloatKeyframes) newPVH.mKeyframes;
13667c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            return newPVH;
13677c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
13687c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
13697c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        /**
13707c608f25d494c8a0a671e7373efbb47ca635367eChet Haase         * Internal function to set the value on the target object, using the setter set up
13717c608f25d494c8a0a671e7373efbb47ca635367eChet Haase         * earlier on this PropertyValuesHolder object. This function is called by ObjectAnimator
13727c608f25d494c8a0a671e7373efbb47ca635367eChet Haase         * to handle turning the value calculated by ValueAnimator into a value set on the object
13737c608f25d494c8a0a671e7373efbb47ca635367eChet Haase         * according to the name of the property.
13747c608f25d494c8a0a671e7373efbb47ca635367eChet Haase         * @param target The target object on which the value is set
13757c608f25d494c8a0a671e7373efbb47ca635367eChet Haase         */
13767c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        @Override
13777c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        void setAnimatedValue(Object target) {
1378b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            if (mFloatProperty != null) {
1379b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                mFloatProperty.setValue(target, mFloatAnimatedValue);
1380b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                return;
1381b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            }
1382b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            if (mProperty != null) {
1383b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                mProperty.set(target, mFloatAnimatedValue);
1384b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                return;
1385b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            }
13866e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            if (mJniSetter != 0) {
13876e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                nCallFloatMethod(target, mJniSetter, mFloatAnimatedValue);
13886e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                return;
13896e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            }
13907c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            if (mSetter != null) {
13917c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                try {
13927c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    mTmpValueArray[0] = mFloatAnimatedValue;
13937c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    mSetter.invoke(target, mTmpValueArray);
13947c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                } catch (InvocationTargetException e) {
13957c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    Log.e("PropertyValuesHolder", e.toString());
13967c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                } catch (IllegalAccessException e) {
13977c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    Log.e("PropertyValuesHolder", e.toString());
13987c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                }
13997c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            }
14007c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
14017c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
14026e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase        @Override
14036e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase        void setupSetter(Class targetClass) {
1404b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            if (mProperty != null) {
1405b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                return;
1406b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            }
14076e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            // Check new static hashmap<propName, int> for setter method
1408691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount            synchronized (sJNISetterPropertyMap) {
1409fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat                HashMap<String, Long> propertyMap = sJNISetterPropertyMap.get(targetClass);
1410691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                boolean wasInMap = false;
14116e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                if (propertyMap != null) {
1412691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    wasInMap = propertyMap.containsKey(mPropertyName);
1413691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    if (wasInMap) {
1414691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        Long jniSetter = propertyMap.get(mPropertyName);
1415691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        if (jniSetter != null) {
1416691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                            mJniSetter = jniSetter;
1417691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        }
14186e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                    }
14196e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                }
1420691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                if (!wasInMap) {
14216e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                    String methodName = getMethodName("set", mPropertyName);
1422691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    try {
1423691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        mJniSetter = nGetFloatMethod(targetClass, methodName);
1424691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    } catch (NoSuchMethodError e) {
1425691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        // Couldn't find it via JNI - try reflection next. Probably means the method
1426691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        // doesn't exist, or the type is wrong. An error will be logged later if
1427691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        // reflection fails as well.
1428691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    }
1429691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    if (propertyMap == null) {
1430691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        propertyMap = new HashMap<String, Long>();
1431691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        sJNISetterPropertyMap.put(targetClass, propertyMap);
14326e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                    }
1433691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    propertyMap.put(mPropertyName, mJniSetter);
14346e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                }
14356e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            }
14366e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            if (mJniSetter == 0) {
14376e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                // Couldn't find method through fast JNI approach - just use reflection
14386e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                super.setupSetter(targetClass);
14396e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            }
14406e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase        }
14416e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase
14427c608f25d494c8a0a671e7373efbb47ca635367eChet Haase    }
14436e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase
14444eed52944c0fcb3afa7369aba60fb5c655580286George Mount    static class MultiFloatValuesHolder extends PropertyValuesHolder {
1445fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat        private long mJniSetter;
1446fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat        private static final HashMap<Class, HashMap<String, Long>> sJNISetterPropertyMap =
1447fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat                new HashMap<Class, HashMap<String, Long>>();
14484eed52944c0fcb3afa7369aba60fb5c655580286George Mount
14494eed52944c0fcb3afa7369aba60fb5c655580286George Mount        public MultiFloatValuesHolder(String propertyName, TypeConverter converter,
14504eed52944c0fcb3afa7369aba60fb5c655580286George Mount                TypeEvaluator evaluator, Object... values) {
14514eed52944c0fcb3afa7369aba60fb5c655580286George Mount            super(propertyName);
14524eed52944c0fcb3afa7369aba60fb5c655580286George Mount            setConverter(converter);
14534eed52944c0fcb3afa7369aba60fb5c655580286George Mount            setObjectValues(values);
14544eed52944c0fcb3afa7369aba60fb5c655580286George Mount            setEvaluator(evaluator);
14554eed52944c0fcb3afa7369aba60fb5c655580286George Mount        }
14564eed52944c0fcb3afa7369aba60fb5c655580286George Mount
14574eed52944c0fcb3afa7369aba60fb5c655580286George Mount        public MultiFloatValuesHolder(String propertyName, TypeConverter converter,
1458984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                TypeEvaluator evaluator, Keyframes keyframes) {
14594eed52944c0fcb3afa7369aba60fb5c655580286George Mount            super(propertyName);
14604eed52944c0fcb3afa7369aba60fb5c655580286George Mount            setConverter(converter);
1461984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            mKeyframes = keyframes;
14624eed52944c0fcb3afa7369aba60fb5c655580286George Mount            setEvaluator(evaluator);
14634eed52944c0fcb3afa7369aba60fb5c655580286George Mount        }
14644eed52944c0fcb3afa7369aba60fb5c655580286George Mount
14654eed52944c0fcb3afa7369aba60fb5c655580286George Mount        /**
14664eed52944c0fcb3afa7369aba60fb5c655580286George Mount         * Internal function to set the value on the target object, using the setter set up
14674eed52944c0fcb3afa7369aba60fb5c655580286George Mount         * earlier on this PropertyValuesHolder object. This function is called by ObjectAnimator
14684eed52944c0fcb3afa7369aba60fb5c655580286George Mount         * to handle turning the value calculated by ValueAnimator into a value set on the object
14694eed52944c0fcb3afa7369aba60fb5c655580286George Mount         * according to the name of the property.
14704eed52944c0fcb3afa7369aba60fb5c655580286George Mount         *
14714eed52944c0fcb3afa7369aba60fb5c655580286George Mount         * @param target The target object on which the value is set
14724eed52944c0fcb3afa7369aba60fb5c655580286George Mount         */
14734eed52944c0fcb3afa7369aba60fb5c655580286George Mount        @Override
14744eed52944c0fcb3afa7369aba60fb5c655580286George Mount        void setAnimatedValue(Object target) {
14754eed52944c0fcb3afa7369aba60fb5c655580286George Mount            float[] values = (float[]) getAnimatedValue();
14764eed52944c0fcb3afa7369aba60fb5c655580286George Mount            int numParameters = values.length;
14774eed52944c0fcb3afa7369aba60fb5c655580286George Mount            if (mJniSetter != 0) {
14784eed52944c0fcb3afa7369aba60fb5c655580286George Mount                switch (numParameters) {
14794eed52944c0fcb3afa7369aba60fb5c655580286George Mount                    case 1:
14804eed52944c0fcb3afa7369aba60fb5c655580286George Mount                        nCallFloatMethod(target, mJniSetter, values[0]);
14814eed52944c0fcb3afa7369aba60fb5c655580286George Mount                        break;
14824eed52944c0fcb3afa7369aba60fb5c655580286George Mount                    case 2:
14834eed52944c0fcb3afa7369aba60fb5c655580286George Mount                        nCallTwoFloatMethod(target, mJniSetter, values[0], values[1]);
14844eed52944c0fcb3afa7369aba60fb5c655580286George Mount                        break;
14854eed52944c0fcb3afa7369aba60fb5c655580286George Mount                    case 4:
14864eed52944c0fcb3afa7369aba60fb5c655580286George Mount                        nCallFourFloatMethod(target, mJniSetter, values[0], values[1],
14874eed52944c0fcb3afa7369aba60fb5c655580286George Mount                                values[2], values[3]);
14884eed52944c0fcb3afa7369aba60fb5c655580286George Mount                        break;
14894eed52944c0fcb3afa7369aba60fb5c655580286George Mount                    default: {
14904eed52944c0fcb3afa7369aba60fb5c655580286George Mount                        nCallMultipleFloatMethod(target, mJniSetter, values);
14914eed52944c0fcb3afa7369aba60fb5c655580286George Mount                        break;
14924eed52944c0fcb3afa7369aba60fb5c655580286George Mount                    }
14934eed52944c0fcb3afa7369aba60fb5c655580286George Mount                }
14944eed52944c0fcb3afa7369aba60fb5c655580286George Mount            }
14954eed52944c0fcb3afa7369aba60fb5c655580286George Mount        }
14964eed52944c0fcb3afa7369aba60fb5c655580286George Mount
14974eed52944c0fcb3afa7369aba60fb5c655580286George Mount        /**
14984eed52944c0fcb3afa7369aba60fb5c655580286George Mount         * Internal function (called from ObjectAnimator) to set up the setter and getter
14994eed52944c0fcb3afa7369aba60fb5c655580286George Mount         * prior to running the animation. No getter can be used for multiple parameters.
15004eed52944c0fcb3afa7369aba60fb5c655580286George Mount         *
15014eed52944c0fcb3afa7369aba60fb5c655580286George Mount         * @param target The object on which the setter exists.
15024eed52944c0fcb3afa7369aba60fb5c655580286George Mount         */
15034eed52944c0fcb3afa7369aba60fb5c655580286George Mount        @Override
15044eed52944c0fcb3afa7369aba60fb5c655580286George Mount        void setupSetterAndGetter(Object target) {
15054eed52944c0fcb3afa7369aba60fb5c655580286George Mount            setupSetter(target.getClass());
15064eed52944c0fcb3afa7369aba60fb5c655580286George Mount        }
15074eed52944c0fcb3afa7369aba60fb5c655580286George Mount
15084eed52944c0fcb3afa7369aba60fb5c655580286George Mount        @Override
15094eed52944c0fcb3afa7369aba60fb5c655580286George Mount        void setupSetter(Class targetClass) {
15104eed52944c0fcb3afa7369aba60fb5c655580286George Mount            if (mJniSetter != 0) {
15114eed52944c0fcb3afa7369aba60fb5c655580286George Mount                return;
15124eed52944c0fcb3afa7369aba60fb5c655580286George Mount            }
1513691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount            synchronized(sJNISetterPropertyMap) {
1514fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat                HashMap<String, Long> propertyMap = sJNISetterPropertyMap.get(targetClass);
1515691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                boolean wasInMap = false;
15164eed52944c0fcb3afa7369aba60fb5c655580286George Mount                if (propertyMap != null) {
1517691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    wasInMap = propertyMap.containsKey(mPropertyName);
1518691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    if (wasInMap) {
1519691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        Long jniSetter = propertyMap.get(mPropertyName);
1520691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        if (jniSetter != null) {
1521691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                            mJniSetter = jniSetter;
1522691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        }
15234eed52944c0fcb3afa7369aba60fb5c655580286George Mount                    }
15244eed52944c0fcb3afa7369aba60fb5c655580286George Mount                }
1525691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                if (!wasInMap) {
15264eed52944c0fcb3afa7369aba60fb5c655580286George Mount                    String methodName = getMethodName("set", mPropertyName);
15274eed52944c0fcb3afa7369aba60fb5c655580286George Mount                    calculateValue(0f);
15284eed52944c0fcb3afa7369aba60fb5c655580286George Mount                    float[] values = (float[]) getAnimatedValue();
15294eed52944c0fcb3afa7369aba60fb5c655580286George Mount                    int numParams = values.length;
15304eed52944c0fcb3afa7369aba60fb5c655580286George Mount                    try {
15314eed52944c0fcb3afa7369aba60fb5c655580286George Mount                        mJniSetter = nGetMultipleFloatMethod(targetClass, methodName, numParams);
15324eed52944c0fcb3afa7369aba60fb5c655580286George Mount                    } catch (NoSuchMethodError e) {
15334eed52944c0fcb3afa7369aba60fb5c655580286George Mount                        // try without the 'set' prefix
1534691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        try {
1535691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                            mJniSetter = nGetMultipleFloatMethod(targetClass, mPropertyName,
1536691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                                    numParams);
1537691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        } catch (NoSuchMethodError e2) {
1538691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                            // just try reflection next
15394eed52944c0fcb3afa7369aba60fb5c655580286George Mount                        }
15404eed52944c0fcb3afa7369aba60fb5c655580286George Mount                    }
1541691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    if (propertyMap == null) {
1542691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        propertyMap = new HashMap<String, Long>();
1543691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        sJNISetterPropertyMap.put(targetClass, propertyMap);
1544691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    }
1545691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    propertyMap.put(mPropertyName, mJniSetter);
15464eed52944c0fcb3afa7369aba60fb5c655580286George Mount                }
15479f3b31b9530a2121b4557fc312972c4faa133d5eDoris Liu            }
15484eed52944c0fcb3afa7369aba60fb5c655580286George Mount        }
15494eed52944c0fcb3afa7369aba60fb5c655580286George Mount    }
15504eed52944c0fcb3afa7369aba60fb5c655580286George Mount
15514eed52944c0fcb3afa7369aba60fb5c655580286George Mount    static class MultiIntValuesHolder extends PropertyValuesHolder {
1552fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat        private long mJniSetter;
1553fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat        private static final HashMap<Class, HashMap<String, Long>> sJNISetterPropertyMap =
1554fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat                new HashMap<Class, HashMap<String, Long>>();
15554eed52944c0fcb3afa7369aba60fb5c655580286George Mount
15564eed52944c0fcb3afa7369aba60fb5c655580286George Mount        public MultiIntValuesHolder(String propertyName, TypeConverter converter,
15574eed52944c0fcb3afa7369aba60fb5c655580286George Mount                TypeEvaluator evaluator, Object... values) {
15584eed52944c0fcb3afa7369aba60fb5c655580286George Mount            super(propertyName);
15594eed52944c0fcb3afa7369aba60fb5c655580286George Mount            setConverter(converter);
15604eed52944c0fcb3afa7369aba60fb5c655580286George Mount            setObjectValues(values);
15614eed52944c0fcb3afa7369aba60fb5c655580286George Mount            setEvaluator(evaluator);
15624eed52944c0fcb3afa7369aba60fb5c655580286George Mount        }
15634eed52944c0fcb3afa7369aba60fb5c655580286George Mount
15644eed52944c0fcb3afa7369aba60fb5c655580286George Mount        public MultiIntValuesHolder(String propertyName, TypeConverter converter,
1565984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                TypeEvaluator evaluator, Keyframes keyframes) {
15664eed52944c0fcb3afa7369aba60fb5c655580286George Mount            super(propertyName);
15674eed52944c0fcb3afa7369aba60fb5c655580286George Mount            setConverter(converter);
1568984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount            mKeyframes = keyframes;
15694eed52944c0fcb3afa7369aba60fb5c655580286George Mount            setEvaluator(evaluator);
15704eed52944c0fcb3afa7369aba60fb5c655580286George Mount        }
15714eed52944c0fcb3afa7369aba60fb5c655580286George Mount
15724eed52944c0fcb3afa7369aba60fb5c655580286George Mount        /**
15734eed52944c0fcb3afa7369aba60fb5c655580286George Mount         * Internal function to set the value on the target object, using the setter set up
15744eed52944c0fcb3afa7369aba60fb5c655580286George Mount         * earlier on this PropertyValuesHolder object. This function is called by ObjectAnimator
15754eed52944c0fcb3afa7369aba60fb5c655580286George Mount         * to handle turning the value calculated by ValueAnimator into a value set on the object
15764eed52944c0fcb3afa7369aba60fb5c655580286George Mount         * according to the name of the property.
15774eed52944c0fcb3afa7369aba60fb5c655580286George Mount         *
15784eed52944c0fcb3afa7369aba60fb5c655580286George Mount         * @param target The target object on which the value is set
15794eed52944c0fcb3afa7369aba60fb5c655580286George Mount         */
15804eed52944c0fcb3afa7369aba60fb5c655580286George Mount        @Override
15814eed52944c0fcb3afa7369aba60fb5c655580286George Mount        void setAnimatedValue(Object target) {
15824eed52944c0fcb3afa7369aba60fb5c655580286George Mount            int[] values = (int[]) getAnimatedValue();
15834eed52944c0fcb3afa7369aba60fb5c655580286George Mount            int numParameters = values.length;
15844eed52944c0fcb3afa7369aba60fb5c655580286George Mount            if (mJniSetter != 0) {
15854eed52944c0fcb3afa7369aba60fb5c655580286George Mount                switch (numParameters) {
15864eed52944c0fcb3afa7369aba60fb5c655580286George Mount                    case 1:
15874eed52944c0fcb3afa7369aba60fb5c655580286George Mount                        nCallIntMethod(target, mJniSetter, values[0]);
15884eed52944c0fcb3afa7369aba60fb5c655580286George Mount                        break;
15894eed52944c0fcb3afa7369aba60fb5c655580286George Mount                    case 2:
15904eed52944c0fcb3afa7369aba60fb5c655580286George Mount                        nCallTwoIntMethod(target, mJniSetter, values[0], values[1]);
15914eed52944c0fcb3afa7369aba60fb5c655580286George Mount                        break;
15924eed52944c0fcb3afa7369aba60fb5c655580286George Mount                    case 4:
15934eed52944c0fcb3afa7369aba60fb5c655580286George Mount                        nCallFourIntMethod(target, mJniSetter, values[0], values[1],
15944eed52944c0fcb3afa7369aba60fb5c655580286George Mount                                values[2], values[3]);
15954eed52944c0fcb3afa7369aba60fb5c655580286George Mount                        break;
15964eed52944c0fcb3afa7369aba60fb5c655580286George Mount                    default: {
15974eed52944c0fcb3afa7369aba60fb5c655580286George Mount                        nCallMultipleIntMethod(target, mJniSetter, values);
15984eed52944c0fcb3afa7369aba60fb5c655580286George Mount                        break;
15994eed52944c0fcb3afa7369aba60fb5c655580286George Mount                    }
16004eed52944c0fcb3afa7369aba60fb5c655580286George Mount                }
16014eed52944c0fcb3afa7369aba60fb5c655580286George Mount            }
16024eed52944c0fcb3afa7369aba60fb5c655580286George Mount        }
16034eed52944c0fcb3afa7369aba60fb5c655580286George Mount
16044eed52944c0fcb3afa7369aba60fb5c655580286George Mount        /**
16054eed52944c0fcb3afa7369aba60fb5c655580286George Mount         * Internal function (called from ObjectAnimator) to set up the setter and getter
16064eed52944c0fcb3afa7369aba60fb5c655580286George Mount         * prior to running the animation. No getter can be used for multiple parameters.
16074eed52944c0fcb3afa7369aba60fb5c655580286George Mount         *
16084eed52944c0fcb3afa7369aba60fb5c655580286George Mount         * @param target The object on which the setter exists.
16094eed52944c0fcb3afa7369aba60fb5c655580286George Mount         */
16104eed52944c0fcb3afa7369aba60fb5c655580286George Mount        @Override
16114eed52944c0fcb3afa7369aba60fb5c655580286George Mount        void setupSetterAndGetter(Object target) {
16124eed52944c0fcb3afa7369aba60fb5c655580286George Mount            setupSetter(target.getClass());
16134eed52944c0fcb3afa7369aba60fb5c655580286George Mount        }
16144eed52944c0fcb3afa7369aba60fb5c655580286George Mount
16154eed52944c0fcb3afa7369aba60fb5c655580286George Mount        @Override
16164eed52944c0fcb3afa7369aba60fb5c655580286George Mount        void setupSetter(Class targetClass) {
16174eed52944c0fcb3afa7369aba60fb5c655580286George Mount            if (mJniSetter != 0) {
16184eed52944c0fcb3afa7369aba60fb5c655580286George Mount                return;
16194eed52944c0fcb3afa7369aba60fb5c655580286George Mount            }
1620691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount            synchronized(sJNISetterPropertyMap) {
1621fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat                HashMap<String, Long> propertyMap = sJNISetterPropertyMap.get(targetClass);
1622691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                boolean wasInMap = false;
16234eed52944c0fcb3afa7369aba60fb5c655580286George Mount                if (propertyMap != null) {
1624691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    wasInMap = propertyMap.containsKey(mPropertyName);
1625691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    if (wasInMap) {
1626691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        Long jniSetter = propertyMap.get(mPropertyName);
1627691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        if (jniSetter != null) {
1628691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                            mJniSetter = jniSetter;
1629691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        }
16304eed52944c0fcb3afa7369aba60fb5c655580286George Mount                    }
16314eed52944c0fcb3afa7369aba60fb5c655580286George Mount                }
1632691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                if (!wasInMap) {
16334eed52944c0fcb3afa7369aba60fb5c655580286George Mount                    String methodName = getMethodName("set", mPropertyName);
16344eed52944c0fcb3afa7369aba60fb5c655580286George Mount                    calculateValue(0f);
16354eed52944c0fcb3afa7369aba60fb5c655580286George Mount                    int[] values = (int[]) getAnimatedValue();
16364eed52944c0fcb3afa7369aba60fb5c655580286George Mount                    int numParams = values.length;
16374eed52944c0fcb3afa7369aba60fb5c655580286George Mount                    try {
16384eed52944c0fcb3afa7369aba60fb5c655580286George Mount                        mJniSetter = nGetMultipleIntMethod(targetClass, methodName, numParams);
16394eed52944c0fcb3afa7369aba60fb5c655580286George Mount                    } catch (NoSuchMethodError e) {
16404eed52944c0fcb3afa7369aba60fb5c655580286George Mount                        // try without the 'set' prefix
1641691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        try {
1642691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                            mJniSetter = nGetMultipleIntMethod(targetClass, mPropertyName,
1643691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                                    numParams);
1644691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        } catch (NoSuchMethodError e2) {
1645691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                            // couldn't find it.
16464eed52944c0fcb3afa7369aba60fb5c655580286George Mount                        }
16474eed52944c0fcb3afa7369aba60fb5c655580286George Mount                    }
1648691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    if (propertyMap == null) {
1649691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        propertyMap = new HashMap<String, Long>();
1650691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                        sJNISetterPropertyMap.put(targetClass, propertyMap);
1651691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    }
1652691487d2c370dc2c7dbf360a25244b99651c18afGeorge Mount                    propertyMap.put(mPropertyName, mJniSetter);
16534eed52944c0fcb3afa7369aba60fb5c655580286George Mount                }
16544eed52944c0fcb3afa7369aba60fb5c655580286George Mount            }
16554eed52944c0fcb3afa7369aba60fb5c655580286George Mount        }
16564eed52944c0fcb3afa7369aba60fb5c655580286George Mount    }
16574eed52944c0fcb3afa7369aba60fb5c655580286George Mount
1658c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount    /**
1659c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * Convert from PointF to float[] for multi-float setters along a Path.
1660c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     */
1661c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount    private static class PointFToFloatArray extends TypeConverter<PointF, float[]> {
1662c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount        private float[] mCoordinates = new float[2];
1663c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount
1664c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount        public PointFToFloatArray() {
1665c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount            super(PointF.class, float[].class);
1666c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount        }
1667c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount
1668c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount        @Override
1669c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount        public float[] convert(PointF value) {
1670c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount            mCoordinates[0] = value.x;
1671c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount            mCoordinates[1] = value.y;
1672c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount            return mCoordinates;
1673c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount        }
1674c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount    };
1675c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount
1676c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount    /**
1677c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     * Convert from PointF to int[] for multi-int setters along a Path.
1678c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount     */
1679c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount    private static class PointFToIntArray extends TypeConverter<PointF, int[]> {
1680c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount        private int[] mCoordinates = new int[2];
1681c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount
1682c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount        public PointFToIntArray() {
1683c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount            super(PointF.class, int[].class);
1684c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount        }
1685c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount
1686c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount        @Override
1687c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount        public int[] convert(PointF value) {
1688c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount            mCoordinates[0] = Math.round(value.x);
1689c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount            mCoordinates[1] = Math.round(value.y);
1690c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount            return mCoordinates;
1691c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount        }
1692c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount    };
1693c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount
1694766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu    /**
1695766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu     * @hide
1696766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu     */
1697766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu    public static class PropertyValues {
1698766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu        public String propertyName;
1699766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu        public Class type;
1700766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu        public Object startValue;
1701766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu        public Object endValue;
1702766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu        public DataSource dataSource = null;
1703766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu        public interface DataSource {
1704766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu            Object getValueAtFraction(float fraction);
1705766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu        }
1706766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu        public String toString() {
1707766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu            return ("property name: " + propertyName + ", type: " + type + ", startValue: "
1708766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu                    + startValue.toString() + ", endValue: " + endValue.toString());
1709766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu        }
1710766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu    }
1711766431aa57c16ece8842287a92b2e7208e3b8ac3Doris Liu
1712fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat    native static private long nGetIntMethod(Class targetClass, String methodName);
1713fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat    native static private long nGetFloatMethod(Class targetClass, String methodName);
1714fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat    native static private long nGetMultipleIntMethod(Class targetClass, String methodName,
17154eed52944c0fcb3afa7369aba60fb5c655580286George Mount            int numParams);
1716fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat    native static private long nGetMultipleFloatMethod(Class targetClass, String methodName,
17174eed52944c0fcb3afa7369aba60fb5c655580286George Mount            int numParams);
1718fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat    native static private void nCallIntMethod(Object target, long methodID, int arg);
1719fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat    native static private void nCallFloatMethod(Object target, long methodID, float arg);
1720fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat    native static private void nCallTwoIntMethod(Object target, long methodID, int arg1, int arg2);
1721fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat    native static private void nCallFourIntMethod(Object target, long methodID, int arg1, int arg2,
17224eed52944c0fcb3afa7369aba60fb5c655580286George Mount            int arg3, int arg4);
1723fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat    native static private void nCallMultipleIntMethod(Object target, long methodID, int[] args);
1724fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat    native static private void nCallTwoFloatMethod(Object target, long methodID, float arg1,
17254eed52944c0fcb3afa7369aba60fb5c655580286George Mount            float arg2);
1726fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat    native static private void nCallFourFloatMethod(Object target, long methodID, float arg1,
17274eed52944c0fcb3afa7369aba60fb5c655580286George Mount            float arg2, float arg3, float arg4);
1728fbb35fb39eb74c6fa7ba6804faeaccb80483be14Ashok Bhat    native static private void nCallMultipleFloatMethod(Object target, long methodID, float[] args);
1729c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7George Mount}
1730