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
19b39f051631250c49936a475d0e64584afb7f1b93Chet Haaseimport android.util.FloatProperty;
20b39f051631250c49936a475d0e64584afb7f1b93Chet Haaseimport android.util.IntProperty;
21d953d08e9299072130d9f4411cbcf6678bbce822Chet Haaseimport android.util.Log;
22b39f051631250c49936a475d0e64584afb7f1b93Chet Haaseimport android.util.Property;
23d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
24d953d08e9299072130d9f4411cbcf6678bbce822Chet Haaseimport java.lang.reflect.InvocationTargetException;
25d953d08e9299072130d9f4411cbcf6678bbce822Chet Haaseimport java.lang.reflect.Method;
26d953d08e9299072130d9f4411cbcf6678bbce822Chet Haaseimport java.util.HashMap;
27d953d08e9299072130d9f4411cbcf6678bbce822Chet Haaseimport java.util.concurrent.locks.ReentrantReadWriteLock;
28d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
29d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase/**
3021cd1389d2ef218b20994b617c57af120841a57fChet Haase * This class holds information about a property and the values that that property
3121cd1389d2ef218b20994b617c57af120841a57fChet Haase * should take on during an animation. PropertyValuesHolder objects can be used to create
32a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * animations with ValueAnimator or ObjectAnimator that operate on several different properties
3321cd1389d2ef218b20994b617c57af120841a57fChet Haase * in parallel.
34d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase */
352794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haasepublic class PropertyValuesHolder implements Cloneable {
36d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
37d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
38d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * The name of the property associated with the values. This need not be a real property,
39a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * unless this object is being used with ObjectAnimator. But this is the name by which
40a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * aniamted values are looked up with getAnimatedValue(String) in ValueAnimator.
41d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
426e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase    String mPropertyName;
43d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
44d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
45b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @hide
46b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     */
47b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    protected Property mProperty;
48b39f051631250c49936a475d0e64584afb7f1b93Chet Haase
49b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    /**
50a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * The setter function, if needed. ObjectAnimator hands off this functionality to
51d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * PropertyValuesHolder, since it holds all of the per-property information. This
5237f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase     * property is automatically
53a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * derived when the animation starts in setupSetterAndGetter() if using ObjectAnimator.
54d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
557c608f25d494c8a0a671e7373efbb47ca635367eChet Haase    Method mSetter = null;
56d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
57d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
58a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * The getter function, if needed. ObjectAnimator hands off this functionality to
59d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * PropertyValuesHolder, since it holds all of the per-property information. This
6037f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase     * property is automatically
61a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * derived when the animation starts in setupSetterAndGetter() if using ObjectAnimator.
62d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * The getter is only derived and used if one of the values is null.
63d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
64d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    private Method mGetter = null;
65d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
66d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
67d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * The type of values supplied. This information is used both in deriving the setter/getter
68d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * functions and in deriving the type of TypeEvaluator.
69d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
707c608f25d494c8a0a671e7373efbb47ca635367eChet Haase    Class mValueType;
71d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
72d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
73d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * The set of keyframes (time/value pairs) that define this animation.
74d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
757c608f25d494c8a0a671e7373efbb47ca635367eChet Haase    KeyframeSet mKeyframeSet = null;
76d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
77d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
78b2ab04ffb6894f399d5c9ceb15f64eb17b654426Chet Haase    // type evaluators for the primitive types handled by this implementation
79d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    private static final TypeEvaluator sIntEvaluator = new IntEvaluator();
80d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    private static final TypeEvaluator sFloatEvaluator = new FloatEvaluator();
81d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
82d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    // We try several different types when searching for appropriate setter/getter functions.
83d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    // The caller may have supplied values in a type that does not match the setter/getter
84d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    // functions (such as the integers 0 and 1 to represent floating point values for alpha).
85d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    // Also, the use of generics in constructors means that we end up with the Object versions
86d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    // of primitive types (Float vs. float). But most likely, the setter/getter functions
87d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    // will take primitive types instead.
88d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    // So we supply an ordered array of other types to try before giving up.
89d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    private static Class[] FLOAT_VARIANTS = {float.class, Float.class, double.class, int.class,
90d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            Double.class, Integer.class};
91d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    private static Class[] INTEGER_VARIANTS = {int.class, Integer.class, float.class, double.class,
92d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            Float.class, Double.class};
93d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    private static Class[] DOUBLE_VARIANTS = {double.class, Double.class, float.class, int.class,
94d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            Float.class, Integer.class};
95d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
96d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    // These maps hold all property entries for a particular class. This map
97d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    // is used to speed up property/setter/getter lookups for a given class/property
98d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    // combination. No need to use reflection on the combination more than once.
99d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    private static final HashMap<Class, HashMap<String, Method>> sSetterPropertyMap =
100d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            new HashMap<Class, HashMap<String, Method>>();
101d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    private static final HashMap<Class, HashMap<String, Method>> sGetterPropertyMap =
102d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            new HashMap<Class, HashMap<String, Method>>();
103d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
104d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    // This lock is used to ensure that only one thread is accessing the property maps
105d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    // at a time.
1066e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase    final ReentrantReadWriteLock mPropertyMapLock = new ReentrantReadWriteLock();
107d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
108d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    // Used to pass single value to varargs parameter in setter invocation
1096e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase    final Object[] mTmpValueArray = new Object[1];
110d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
111d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
112d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * The type evaluator used to calculate the animated values. This evaluator is determined
113d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * automatically based on the type of the start/end objects passed into the constructor,
114b2ab04ffb6894f399d5c9ceb15f64eb17b654426Chet Haase     * but the system only knows about the primitive types int and float. Any other
115d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * type will need to set the evaluator to a custom evaluator for that type.
116d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
117d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    private TypeEvaluator mEvaluator;
118d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
119d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
120d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * The value most recently calculated by calculateValue(). This is set during
121a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * that function and might be retrieved later either by ValueAnimator.animatedValue() or
122a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * by the property-setting logic in ObjectAnimator.animatedValue().
123d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
124d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    private Object mAnimatedValue;
125d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
126d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
1272794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * Internal utility constructor, used by the factory methods to set the property name.
1282794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @param propertyName The name of the property for this holder.
129d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
1302794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    private PropertyValuesHolder(String propertyName) {
1312794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase        mPropertyName = propertyName;
1322794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    }
1332794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase
1342794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    /**
135b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * Internal utility constructor, used by the factory methods to set the property.
136b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @param property The property for this holder.
137b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     */
138b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    private PropertyValuesHolder(Property property) {
139b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        mProperty = property;
140b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        if (property != null) {
141b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            mPropertyName = property.getName();
142b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        }
143b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    }
144b39f051631250c49936a475d0e64584afb7f1b93Chet Haase
145b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    /**
1462794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * Constructs and returns a PropertyValuesHolder with a given property name and
1472794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * set of int values.
1482794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @param propertyName The name of the property being animated.
1492794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @param values The values that the named property will animate between.
1502794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
1512794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     */
1522794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    public static PropertyValuesHolder ofInt(String propertyName, int... values) {
153b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        return new IntPropertyValuesHolder(propertyName, values);
154b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    }
155b39f051631250c49936a475d0e64584afb7f1b93Chet Haase
156b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    /**
157b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * Constructs and returns a PropertyValuesHolder with a given property and
158b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * set of int values.
159b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @param property The property being animated. Should not be null.
160b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @param values The values that the property will animate between.
161b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
162b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     */
163b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    public static PropertyValuesHolder ofInt(Property<?, Integer> property, int... values) {
164b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        return new IntPropertyValuesHolder(property, values);
1652794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    }
1662794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase
1672794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    /**
1682794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * Constructs and returns a PropertyValuesHolder with a given property name and
1692794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * set of float values.
1702794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @param propertyName The name of the property being animated.
1712794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @param values The values that the named property will animate between.
1722794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
1732794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     */
1742794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    public static PropertyValuesHolder ofFloat(String propertyName, float... values) {
175b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        return new FloatPropertyValuesHolder(propertyName, values);
176b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    }
177b39f051631250c49936a475d0e64584afb7f1b93Chet Haase
178b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    /**
179b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * Constructs and returns a PropertyValuesHolder with a given property and
180b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * set of float values.
181b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @param property The property being animated. Should not be null.
182b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @param values The values that the property will animate between.
183b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
184b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     */
185b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    public static PropertyValuesHolder ofFloat(Property<?, Float> property, float... values) {
186b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        return new FloatPropertyValuesHolder(property, values);
1872794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    }
1882794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase
1892794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    /**
1902794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * Constructs and returns a PropertyValuesHolder with a given property name and
1912794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * set of Object values. This variant also takes a TypeEvaluator because the system
192b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * cannot automatically interpolate between objects of unknown type.
1932794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     *
1942794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @param propertyName The name of the property being animated.
1952794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @param evaluator A TypeEvaluator that will be called on each animation frame to
196b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * provide the necessary interpolation between the Object values to derive the animated
1972794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * value.
1982794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @param values The values that the named property will animate between.
1992794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
2002794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     */
2012794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    public static PropertyValuesHolder ofObject(String propertyName, TypeEvaluator evaluator,
2022794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase            Object... values) {
2032794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase        PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName);
2042794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase        pvh.setObjectValues(values);
2052794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase        pvh.setEvaluator(evaluator);
2062794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase        return pvh;
207d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
208d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
209d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
210b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * Constructs and returns a PropertyValuesHolder with a given property and
211b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * set of Object values. This variant also takes a TypeEvaluator because the system
212b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * cannot automatically interpolate between objects of unknown type.
213b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     *
214b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @param property The property being animated. Should not be null.
215b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @param evaluator A TypeEvaluator that will be called on each animation frame to
216b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * provide the necessary interpolation between the Object values to derive the animated
217b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * value.
218b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @param values The values that the property will animate between.
219b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
220b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     */
221b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    public static <V> PropertyValuesHolder ofObject(Property property,
222b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            TypeEvaluator<V> evaluator, V... values) {
223b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        PropertyValuesHolder pvh = new PropertyValuesHolder(property);
224b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        pvh.setObjectValues(values);
225b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        pvh.setEvaluator(evaluator);
226b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        return pvh;
227b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    }
228b39f051631250c49936a475d0e64584afb7f1b93Chet Haase
229b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    /**
2302794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * Constructs and returns a PropertyValuesHolder object with the specified property name and set
2312794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * of values. These values can be of any type, but the type should be consistent so that
232d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * an appropriate {@link android.animation.TypeEvaluator} can be found that matches
233d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * the common type.
234d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * <p>If there is only one value, it is assumed to be the end value of an animation,
235d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * and an initial value will be derived, if possible, by calling a getter function
236d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * on the object. Also, if any value is null, the value will be filled in when the animation
237d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * starts in the same way. This mechanism of automatically getting null values only works
238d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * if the PropertyValuesHolder object is used in conjunction
2391a8e404743a27da08d0f2df5480c51725c9b001aChet Haase     * {@link ObjectAnimator}, and with a getter function
2401a8e404743a27da08d0f2df5480c51725c9b001aChet Haase     * derived automatically from <code>propertyName</code>, since otherwise PropertyValuesHolder has
241d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * no way of determining what the value should be.
242d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param propertyName The name of the property associated with this set of values. This
243a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * can be the actual property name to be used when using a ObjectAnimator object, or
244d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * just a name used to get animated values, such as if this object is used with an
245a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * ValueAnimator object.
246d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param values The set of values to animate between.
247d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
2482794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    public static PropertyValuesHolder ofKeyframe(String propertyName, Keyframe... values) {
2497c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        KeyframeSet keyframeSet = KeyframeSet.ofKeyframe(values);
2507c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        if (keyframeSet instanceof IntKeyframeSet) {
2517c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            return new IntPropertyValuesHolder(propertyName, (IntKeyframeSet) keyframeSet);
2527c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        } else if (keyframeSet instanceof FloatKeyframeSet) {
2537c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            return new FloatPropertyValuesHolder(propertyName, (FloatKeyframeSet) keyframeSet);
2547c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
2557c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        else {
2567c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName);
2577c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            pvh.mKeyframeSet = keyframeSet;
2587c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            pvh.mValueType = ((Keyframe)values[0]).getType();
2597c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            return pvh;
2607c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
261d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
262d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
263d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
264b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * Constructs and returns a PropertyValuesHolder object with the specified property and set
265b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * of values. These values can be of any type, but the type should be consistent so that
266b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * an appropriate {@link android.animation.TypeEvaluator} can be found that matches
267b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * the common type.
268b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * <p>If there is only one value, it is assumed to be the end value of an animation,
269b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * and an initial value will be derived, if possible, by calling the property's
270b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * {@link android.util.Property#get(Object)} function.
271b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * Also, if any value is null, the value will be filled in when the animation
272b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * starts in the same way. This mechanism of automatically getting null values only works
273b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * if the PropertyValuesHolder object is used in conjunction with
274b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * {@link ObjectAnimator}, since otherwise PropertyValuesHolder has
275b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * no way of determining what the value should be.
276b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @param property The property associated with this set of values. Should not be null.
277b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @param values The set of values to animate between.
278b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     */
279b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    public static PropertyValuesHolder ofKeyframe(Property property, Keyframe... values) {
280b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        KeyframeSet keyframeSet = KeyframeSet.ofKeyframe(values);
281b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        if (keyframeSet instanceof IntKeyframeSet) {
282b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            return new IntPropertyValuesHolder(property, (IntKeyframeSet) keyframeSet);
283b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        } else if (keyframeSet instanceof FloatKeyframeSet) {
284b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            return new FloatPropertyValuesHolder(property, (FloatKeyframeSet) keyframeSet);
285b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        }
286b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        else {
287b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            PropertyValuesHolder pvh = new PropertyValuesHolder(property);
288b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            pvh.mKeyframeSet = keyframeSet;
289b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            pvh.mValueType = ((Keyframe)values[0]).getType();
290b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            return pvh;
291b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        }
292b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    }
293b39f051631250c49936a475d0e64584afb7f1b93Chet Haase
294b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    /**
2952794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * Set the animated values for this object to this set of ints.
296d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * If there is only one value, it is assumed to be the end value of an animation,
297d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * and an initial value will be derived, if possible, by calling a getter function
298d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * on the object. Also, if any value is null, the value will be filled in when the animation
299d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * starts in the same way. This mechanism of automatically getting null values only works
300d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * if the PropertyValuesHolder object is used in conjunction
3011a8e404743a27da08d0f2df5480c51725c9b001aChet Haase     * {@link ObjectAnimator}, and with a getter function
3021a8e404743a27da08d0f2df5480c51725c9b001aChet Haase     * derived automatically from <code>propertyName</code>, since otherwise PropertyValuesHolder has
303d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * no way of determining what the value should be.
3042794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     *
3052794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @param values One or more values that the animation will animate between.
3062794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     */
3072794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    public void setIntValues(int... values) {
3082794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase        mValueType = int.class;
3092794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase        mKeyframeSet = KeyframeSet.ofInt(values);
3102794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    }
3112794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase
3122794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    /**
3132794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * Set the animated values for this object to this set of floats.
3142794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * If there is only one value, it is assumed to be the end value of an animation,
3152794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * and an initial value will be derived, if possible, by calling a getter function
3162794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * on the object. Also, if any value is null, the value will be filled in when the animation
3172794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * starts in the same way. This mechanism of automatically getting null values only works
3182794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * if the PropertyValuesHolder object is used in conjunction
3191a8e404743a27da08d0f2df5480c51725c9b001aChet Haase     * {@link ObjectAnimator}, and with a getter function
3201a8e404743a27da08d0f2df5480c51725c9b001aChet Haase     * derived automatically from <code>propertyName</code>, since otherwise PropertyValuesHolder has
3212794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * no way of determining what the value should be.
3222794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     *
3232794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @param values One or more values that the animation will animate between.
3242794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     */
3252794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    public void setFloatValues(float... values) {
3262794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase        mValueType = float.class;
3272794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase        mKeyframeSet = KeyframeSet.ofFloat(values);
3282794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    }
3292794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase
3302794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    /**
3312794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * Set the animated values for this object to this set of Keyframes.
3322794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     *
3332794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @param values One or more values that the animation will animate between.
334d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
3352794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    public void setKeyframes(Keyframe... values) {
336d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        int numKeyframes = values.length;
337d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        Keyframe keyframes[] = new Keyframe[Math.max(numKeyframes,2)];
3382794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase        mValueType = ((Keyframe)values[0]).getType();
3392794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase        for (int i = 0; i < numKeyframes; ++i) {
3402794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase            keyframes[i] = (Keyframe)values[i];
341d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        }
342d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        mKeyframeSet = new KeyframeSet(keyframes);
343d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
344d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
3452794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    /**
3462794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * Set the animated values for this object to this set of Objects.
3472794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * If there is only one value, it is assumed to be the end value of an animation,
3482794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * and an initial value will be derived, if possible, by calling a getter function
3492794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * on the object. Also, if any value is null, the value will be filled in when the animation
3502794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * starts in the same way. This mechanism of automatically getting null values only works
3512794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * if the PropertyValuesHolder object is used in conjunction
3521a8e404743a27da08d0f2df5480c51725c9b001aChet Haase     * {@link ObjectAnimator}, and with a getter function
3531a8e404743a27da08d0f2df5480c51725c9b001aChet Haase     * derived automatically from <code>propertyName</code>, since otherwise PropertyValuesHolder has
3542794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * no way of determining what the value should be.
3552794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     *
3562794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     * @param values One or more values that the animation will animate between.
3572794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase     */
3582794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    public void setObjectValues(Object... values) {
3592794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase        mValueType = values[0].getClass();
3602794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase        mKeyframeSet = KeyframeSet.ofObject(values);
3612794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    }
362d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
363d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
364d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * Determine the setter or getter function using the JavaBeans convention of setFoo or
365d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * getFoo for a property named 'foo'. This function figures out what the name of the
366d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * function should be and uses reflection to find the Method with that name on the
367d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * target object.
368d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     *
369d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param targetClass The class to search for the method
370d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param prefix "set" or "get", depending on whether we need a setter or getter.
371d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param valueType The type of the parameter (in the case of a setter). This type
372d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * is derived from the values set on this PropertyValuesHolder. This type is used as
373d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * a first guess at the parameter type, but we check for methods with several different
374d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * types to avoid problems with slight mis-matches between supplied values and actual
375d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * value types used on the setter.
376d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @return Method the method associated with mPropertyName.
377d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
378d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    private Method getPropertyFunction(Class targetClass, String prefix, Class valueType) {
379d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        // TODO: faster implementation...
380d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        Method returnVal = null;
3816e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase        String methodName = getMethodName(prefix, mPropertyName);
382d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        Class args[] = null;
383d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        if (valueType == null) {
384d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            try {
385d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                returnVal = targetClass.getMethod(methodName, args);
386d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            } catch (NoSuchMethodException e) {
387db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase                // Swallow the error, log it later
388d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            }
389d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        } else {
390d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            args = new Class[1];
391d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            Class typeVariants[];
392d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            if (mValueType.equals(Float.class)) {
393d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                typeVariants = FLOAT_VARIANTS;
394d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            } else if (mValueType.equals(Integer.class)) {
395d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                typeVariants = INTEGER_VARIANTS;
396d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            } else if (mValueType.equals(Double.class)) {
397d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                typeVariants = DOUBLE_VARIANTS;
398d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            } else {
399d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                typeVariants = new Class[1];
400d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                typeVariants[0] = mValueType;
401d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            }
402d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            for (Class typeVariant : typeVariants) {
403d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                args[0] = typeVariant;
404d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                try {
405d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                    returnVal = targetClass.getMethod(methodName, args);
40621cd1389d2ef218b20994b617c57af120841a57fChet Haase                    // change the value type to suit
40721cd1389d2ef218b20994b617c57af120841a57fChet Haase                    mValueType = typeVariant;
408d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                    return returnVal;
409d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                } catch (NoSuchMethodException e) {
410d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                    // Swallow the error and keep trying other variants
411d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                }
412d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            }
413602e4d3824bf8b9cb9f817375d195b969712176aChet Haase            // If we got here, then no appropriate function was found
414db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase        }
415db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase
416db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase        if (returnVal == null) {
417db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase            Log.w("PropertyValuesHolder", "Method " +
418db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase                    getMethodName(prefix, mPropertyName) + "() with type " + mValueType +
419db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase                    " not found on target class " + targetClass);
420d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        }
421602e4d3824bf8b9cb9f817375d195b969712176aChet Haase
422d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        return returnVal;
423d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
424d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
425d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
426d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
427d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * Returns the setter or getter requested. This utility function checks whether the
428d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * requested method exists in the propertyMapMap cache. If not, it calls another
429d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * utility function to request the Method from the targetClass directly.
430d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param targetClass The Class on which the requested method should exist.
431d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param propertyMapMap The cache of setters/getters derived so far.
432d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param prefix "set" or "get", for the setter or getter.
433d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param valueType The type of parameter passed into the method (null for getter).
434d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @return Method the method associated with mPropertyName.
435d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
436d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    private Method setupSetterOrGetter(Class targetClass,
437d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            HashMap<Class, HashMap<String, Method>> propertyMapMap,
438d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            String prefix, Class valueType) {
439d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        Method setterOrGetter = null;
440d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        try {
441d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            // Have to lock property map prior to reading it, to guard against
442d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            // another thread putting something in there after we've checked it
443d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            // but before we've added an entry to it
4446e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            mPropertyMapLock.writeLock().lock();
445d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            HashMap<String, Method> propertyMap = propertyMapMap.get(targetClass);
446d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            if (propertyMap != null) {
447d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                setterOrGetter = propertyMap.get(mPropertyName);
448d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            }
449d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            if (setterOrGetter == null) {
450d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                setterOrGetter = getPropertyFunction(targetClass, prefix, valueType);
451d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                if (propertyMap == null) {
452d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                    propertyMap = new HashMap<String, Method>();
453d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                    propertyMapMap.put(targetClass, propertyMap);
454d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                }
455d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                propertyMap.put(mPropertyName, setterOrGetter);
456d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            }
457d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        } finally {
4586e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            mPropertyMapLock.writeLock().unlock();
459d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        }
460d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        return setterOrGetter;
461d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
462d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
463d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
464d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * Utility function to get the setter from targetClass
465d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param targetClass The Class on which the requested method should exist.
466d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
4676e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase    void setupSetter(Class targetClass) {
468d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", mValueType);
469d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
470d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
471d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
472d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * Utility function to get the getter from targetClass
473d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
474d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    private void setupGetter(Class targetClass) {
475d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        mGetter = setupSetterOrGetter(targetClass, sGetterPropertyMap, "get", null);
476d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
477d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
478d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
479a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Internal function (called from ObjectAnimator) to set up the setter and getter
480d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * prior to running the animation. If the setter has not been manually set for this
481d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * object, it will be derived automatically given the property name, target object, and
482d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * types of values supplied. If no getter has been set, it will be supplied iff any of the
483d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * supplied values was null. If there is a null value, then the getter (supplied or derived)
484d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * will be called to set those null values to the current value of the property
485d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * on the target object.
486d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param target The object on which the setter (and possibly getter) exist.
487d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
488d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    void setupSetterAndGetter(Object target) {
489b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        if (mProperty != null) {
490b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            // check to make sure that mProperty is on the class of target
491b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            try {
492b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                Object testValue = mProperty.get(target);
493b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                for (Keyframe kf : mKeyframeSet.mKeyframes) {
494b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                    if (!kf.hasValue()) {
495b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                        kf.setValue(mProperty.get(target));
496b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                    }
497b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                }
498b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                return;
499b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            } catch (ClassCastException e) {
500db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase                Log.w("PropertyValuesHolder","No such property (" + mProperty.getName() +
501b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                        ") on target object " + target + ". Trying reflection instead");
502b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                mProperty = null;
503b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            }
504b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        }
505d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        Class targetClass = target.getClass();
506d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        if (mSetter == null) {
507d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            setupSetter(targetClass);
508d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        }
509d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        for (Keyframe kf : mKeyframeSet.mKeyframes) {
5107c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            if (!kf.hasValue()) {
511d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                if (mGetter == null) {
512d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                    setupGetter(targetClass);
513db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase                    if (mGetter == null) {
514db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase                        // Already logged the error - just return to avoid NPE
515db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase                        return;
516db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase                    }
517d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                }
518d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                try {
5192794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase                    kf.setValue(mGetter.invoke(target));
520d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                } catch (InvocationTargetException e) {
521d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                    Log.e("PropertyValuesHolder", e.toString());
522d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                } catch (IllegalAccessException e) {
523d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                    Log.e("PropertyValuesHolder", e.toString());
524d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                }
525d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            }
526d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        }
527d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
528d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
529d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
53021cd1389d2ef218b20994b617c57af120841a57fChet Haase     * Utility function to set the value stored in a particular Keyframe. The value used is
53121cd1389d2ef218b20994b617c57af120841a57fChet Haase     * whatever the value is for the property name specified in the keyframe on the target object.
53221cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
53321cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param target The target object from which the current value should be extracted.
53421cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param kf The keyframe which holds the property name and value.
53521cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
53621cd1389d2ef218b20994b617c57af120841a57fChet Haase    private void setupValue(Object target, Keyframe kf) {
537b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        if (mProperty != null) {
538b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            kf.setValue(mProperty.get(target));
539b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        }
54021cd1389d2ef218b20994b617c57af120841a57fChet Haase        try {
54121cd1389d2ef218b20994b617c57af120841a57fChet Haase            if (mGetter == null) {
54221cd1389d2ef218b20994b617c57af120841a57fChet Haase                Class targetClass = target.getClass();
54321cd1389d2ef218b20994b617c57af120841a57fChet Haase                setupGetter(targetClass);
544db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase                if (mGetter == null) {
545db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase                    // Already logged the error - just return to avoid NPE
546db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase                    return;
547db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase                }
54821cd1389d2ef218b20994b617c57af120841a57fChet Haase            }
5492794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase            kf.setValue(mGetter.invoke(target));
55021cd1389d2ef218b20994b617c57af120841a57fChet Haase        } catch (InvocationTargetException e) {
55121cd1389d2ef218b20994b617c57af120841a57fChet Haase            Log.e("PropertyValuesHolder", e.toString());
55221cd1389d2ef218b20994b617c57af120841a57fChet Haase        } catch (IllegalAccessException e) {
55321cd1389d2ef218b20994b617c57af120841a57fChet Haase            Log.e("PropertyValuesHolder", e.toString());
55421cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
55521cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
55621cd1389d2ef218b20994b617c57af120841a57fChet Haase
55721cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
558a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * This function is called by ObjectAnimator when setting the start values for an animation.
55921cd1389d2ef218b20994b617c57af120841a57fChet Haase     * The start values are set according to the current values in the target object. The
56021cd1389d2ef218b20994b617c57af120841a57fChet Haase     * property whose value is extracted is whatever is specified by the propertyName of this
56121cd1389d2ef218b20994b617c57af120841a57fChet Haase     * PropertyValuesHolder object.
56221cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
56321cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param target The object which holds the start values that should be set.
56421cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
56521cd1389d2ef218b20994b617c57af120841a57fChet Haase    void setupStartValue(Object target) {
56621cd1389d2ef218b20994b617c57af120841a57fChet Haase        setupValue(target, mKeyframeSet.mKeyframes.get(0));
56721cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
56821cd1389d2ef218b20994b617c57af120841a57fChet Haase
56921cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
570a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * This function is called by ObjectAnimator when setting the end values for an animation.
57121cd1389d2ef218b20994b617c57af120841a57fChet Haase     * The end values are set according to the current values in the target object. The
57221cd1389d2ef218b20994b617c57af120841a57fChet Haase     * property whose value is extracted is whatever is specified by the propertyName of this
57321cd1389d2ef218b20994b617c57af120841a57fChet Haase     * PropertyValuesHolder object.
57421cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
57521cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param target The object which holds the start values that should be set.
57621cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
57721cd1389d2ef218b20994b617c57af120841a57fChet Haase    void setupEndValue(Object target) {
57821cd1389d2ef218b20994b617c57af120841a57fChet Haase        setupValue(target, mKeyframeSet.mKeyframes.get(mKeyframeSet.mKeyframes.size() - 1));
57921cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
58021cd1389d2ef218b20994b617c57af120841a57fChet Haase
58121cd1389d2ef218b20994b617c57af120841a57fChet Haase    @Override
58221cd1389d2ef218b20994b617c57af120841a57fChet Haase    public PropertyValuesHolder clone() {
5837c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        try {
5847c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            PropertyValuesHolder newPVH = (PropertyValuesHolder) super.clone();
5857c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            newPVH.mPropertyName = mPropertyName;
586b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            newPVH.mProperty = mProperty;
5877c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            newPVH.mKeyframeSet = mKeyframeSet.clone();
5887c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            newPVH.mEvaluator = mEvaluator;
5897c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            return newPVH;
5907c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        } catch (CloneNotSupportedException e) {
5917c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            // won't reach here
5927c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            return null;
59321cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
59421cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
5957c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
59621cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
597d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * Internal function to set the value on the target object, using the setter set up
598a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * earlier on this PropertyValuesHolder object. This function is called by ObjectAnimator
599a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * to handle turning the value calculated by ValueAnimator into a value set on the object
600d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * according to the name of the property.
601d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param target The target object on which the value is set
602d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
603d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    void setAnimatedValue(Object target) {
604b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        if (mProperty != null) {
605b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            mProperty.set(target, getAnimatedValue());
606b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        }
607d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        if (mSetter != null) {
608d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            try {
6097c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                mTmpValueArray[0] = getAnimatedValue();
610d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                mSetter.invoke(target, mTmpValueArray);
611d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            } catch (InvocationTargetException e) {
612d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                Log.e("PropertyValuesHolder", e.toString());
613d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            } catch (IllegalAccessException e) {
614d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase                Log.e("PropertyValuesHolder", e.toString());
615d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase            }
616d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        }
617d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
618d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
619d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
620a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Internal function, called by ValueAnimator, to set up the TypeEvaluator that will be used
621d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * to calculate animated values.
622d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
623d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    void init() {
624d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        if (mEvaluator == null) {
625b2ab04ffb6894f399d5c9ceb15f64eb17b654426Chet Haase            // We already handle int and float automatically, but not their Object
6267c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            // equivalents
6277c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            mEvaluator = (mValueType == Integer.class) ? sIntEvaluator :
6287c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    (mValueType == Float.class) ? sFloatEvaluator :
6297c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    null;
6307c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
6317c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        if (mEvaluator != null) {
6327c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            // KeyframeSet knows how to evaluate the common types - only give it a custom
633b2ab04ffb6894f399d5c9ceb15f64eb17b654426Chet Haase            // evaluator if one has been set on this class
6347c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            mKeyframeSet.setEvaluator(mEvaluator);
635d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        }
636d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
637d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
638d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
639d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * The TypeEvaluator will the automatically determined based on the type of values
640d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * supplied to PropertyValuesHolder. The evaluator can be manually set, however, if so
641d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * desired. This may be important in cases where either the type of the values supplied
642d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * do not match the way that they should be interpolated between, or if the values
643d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * are of a custom type or one not currently understood by the animation system. Currently,
644b2ab04ffb6894f399d5c9ceb15f64eb17b654426Chet Haase     * only values of type float and int (and their Object equivalents: Float
645d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * and Integer) are  correctly interpolated; all other types require setting a TypeEvaluator.
646d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param evaluator
647d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
6487c608f25d494c8a0a671e7373efbb47ca635367eChet Haase    public void setEvaluator(TypeEvaluator evaluator) {
649d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        mEvaluator = evaluator;
6507c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        mKeyframeSet.setEvaluator(evaluator);
651d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
652d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
653d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
654d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * Function used to calculate the value according to the evaluator set up for
655a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * this PropertyValuesHolder object. This function is called by ValueAnimator.animateValue().
656d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     *
657d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param fraction The elapsed, interpolated fraction of the animation.
658d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
6597c608f25d494c8a0a671e7373efbb47ca635367eChet Haase    void calculateValue(float fraction) {
6607c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        mAnimatedValue = mKeyframeSet.getValue(fraction);
661d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
662d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
663d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
664d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * Sets the name of the property that will be animated. This name is used to derive
665d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * a setter function that will be called to set animated values.
666d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * For example, a property name of <code>foo</code> will result
667d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * in a call to the function <code>setFoo()</code> on the target object. If either
668d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will
669d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * also be derived and called.
670d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     *
671d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * <p>Note that the setter function derived from this property name
672d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * must take the same parameter type as the
673d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * <code>valueFrom</code> and <code>valueTo</code> properties, otherwise the call to
674d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * the setter function will fail.</p>
675d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     *
676d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @param propertyName The name of the property being animated.
677d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
678d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    public void setPropertyName(String propertyName) {
679d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        mPropertyName = propertyName;
680d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
681d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
682d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
683b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * Sets the property that will be animated.
684b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     *
685b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * <p>Note that if this PropertyValuesHolder object is used with ObjectAnimator, the property
686b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * must exist on the target object specified in that ObjectAnimator.</p>
687b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     *
688b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     * @param property The property being animated.
689b39f051631250c49936a475d0e64584afb7f1b93Chet Haase     */
690b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    public void setProperty(Property property) {
691b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        mProperty = property;
692b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    }
693b39f051631250c49936a475d0e64584afb7f1b93Chet Haase
694b39f051631250c49936a475d0e64584afb7f1b93Chet Haase    /**
695d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * Gets the name of the property that will be animated. This name will be used to derive
696d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * a setter function that will be called to set animated values.
697d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * For example, a property name of <code>foo</code> will result
698d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * in a call to the function <code>setFoo()</code> on the target object. If either
699d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will
700d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * also be derived and called.
701d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
702d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    public String getPropertyName() {
703d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        return mPropertyName;
704d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
705d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase
706d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    /**
707a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Internal function, called by ValueAnimator and ObjectAnimator, to retrieve the value
708d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * most recently calculated in calculateValue().
709d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     * @return
710d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase     */
711d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    Object getAnimatedValue() {
712d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase        return mAnimatedValue;
713d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase    }
7147c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
715e9140a72b1059574046a624b471b2c3a35806496Chet Haase    @Override
716e9140a72b1059574046a624b471b2c3a35806496Chet Haase    public String toString() {
717e9140a72b1059574046a624b471b2c3a35806496Chet Haase        return mPropertyName + ": " + mKeyframeSet.toString();
718e9140a72b1059574046a624b471b2c3a35806496Chet Haase    }
719e9140a72b1059574046a624b471b2c3a35806496Chet Haase
7206e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase    /**
7216e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase     * Utility method to derive a setter/getter method name from a property name, where the
7226e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase     * prefix is typically "set" or "get" and the first letter of the property name is
7236e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase     * capitalized.
7246e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase     *
7256e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase     * @param prefix The precursor to the method name, before the property name begins, typically
7266e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase     * "set" or "get".
7276e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase     * @param propertyName The name of the property that represents the bulk of the method name
7286e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase     * after the prefix. The first letter of this word will be capitalized in the resulting
7296e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase     * method name.
7306e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase     * @return String the property name converted to a method name according to the conventions
7316e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase     * specified above.
7326e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase     */
7336e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase    static String getMethodName(String prefix, String propertyName) {
734b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        if (propertyName == null || propertyName.length() == 0) {
735b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            // shouldn't get here
736b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            return prefix;
737b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        }
738b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        char firstLetter = Character.toUpperCase(propertyName.charAt(0));
7396e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase        String theRest = propertyName.substring(1);
7406e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase        return prefix + firstLetter + theRest;
7416e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase    }
7426e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase
7437c608f25d494c8a0a671e7373efbb47ca635367eChet Haase    static class IntPropertyValuesHolder extends PropertyValuesHolder {
7447c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
745b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        // Cache JNI functions to avoid looking them up twice
7466e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase        private static final HashMap<Class, HashMap<String, Integer>> sJNISetterPropertyMap =
7476e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                new HashMap<Class, HashMap<String, Integer>>();
7486e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase        int mJniSetter;
749b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        private IntProperty mIntProperty;
7506e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase
7517c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        IntKeyframeSet mIntKeyframeSet;
7527c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        int mIntAnimatedValue;
7537c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
7547c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        public IntPropertyValuesHolder(String propertyName, IntKeyframeSet keyframeSet) {
7557c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            super(propertyName);
7567c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            mValueType = int.class;
7577c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            mKeyframeSet = keyframeSet;
7587c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            mIntKeyframeSet = (IntKeyframeSet) mKeyframeSet;
7597c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
7607c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
761b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        public IntPropertyValuesHolder(Property property, IntKeyframeSet keyframeSet) {
762b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            super(property);
763b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            mValueType = int.class;
764b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            mKeyframeSet = keyframeSet;
765b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            mIntKeyframeSet = (IntKeyframeSet) mKeyframeSet;
766b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            if (property instanceof  IntProperty) {
767b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                mIntProperty = (IntProperty) mProperty;
768b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            }
769b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        }
770b39f051631250c49936a475d0e64584afb7f1b93Chet Haase
7717c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        public IntPropertyValuesHolder(String propertyName, int... values) {
7727c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            super(propertyName);
7737c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            setIntValues(values);
774691ac26817d489d9770aa6ba7b098ff17e8be99aChet Haase        }
775691ac26817d489d9770aa6ba7b098ff17e8be99aChet Haase
776b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        public IntPropertyValuesHolder(Property property, int... values) {
777b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            super(property);
778b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            setIntValues(values);
779b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            if (property instanceof  IntProperty) {
780b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                mIntProperty = (IntProperty) mProperty;
781b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            }
782b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        }
783b39f051631250c49936a475d0e64584afb7f1b93Chet Haase
784691ac26817d489d9770aa6ba7b098ff17e8be99aChet Haase        @Override
785691ac26817d489d9770aa6ba7b098ff17e8be99aChet Haase        public void setIntValues(int... values) {
786691ac26817d489d9770aa6ba7b098ff17e8be99aChet Haase            super.setIntValues(values);
7877c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            mIntKeyframeSet = (IntKeyframeSet) mKeyframeSet;
7887c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
7897c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
7907c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        @Override
7917c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        void calculateValue(float fraction) {
7927c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            mIntAnimatedValue = mIntKeyframeSet.getIntValue(fraction);
7937c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
7947c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
7957c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        @Override
7967c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        Object getAnimatedValue() {
7977c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            return mIntAnimatedValue;
7987c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
7997c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
8007c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        @Override
8017c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        public IntPropertyValuesHolder clone() {
8027c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            IntPropertyValuesHolder newPVH = (IntPropertyValuesHolder) super.clone();
8037c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            newPVH.mIntKeyframeSet = (IntKeyframeSet) newPVH.mKeyframeSet;
8047c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            return newPVH;
8057c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
8067c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
8077c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        /**
8087c608f25d494c8a0a671e7373efbb47ca635367eChet Haase         * Internal function to set the value on the target object, using the setter set up
8097c608f25d494c8a0a671e7373efbb47ca635367eChet Haase         * earlier on this PropertyValuesHolder object. This function is called by ObjectAnimator
8107c608f25d494c8a0a671e7373efbb47ca635367eChet Haase         * to handle turning the value calculated by ValueAnimator into a value set on the object
8117c608f25d494c8a0a671e7373efbb47ca635367eChet Haase         * according to the name of the property.
8127c608f25d494c8a0a671e7373efbb47ca635367eChet Haase         * @param target The target object on which the value is set
8137c608f25d494c8a0a671e7373efbb47ca635367eChet Haase         */
8147c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        @Override
8157c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        void setAnimatedValue(Object target) {
816b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            if (mIntProperty != null) {
817b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                mIntProperty.setValue(target, mIntAnimatedValue);
818b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                return;
819b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            }
820b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            if (mProperty != null) {
821b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                mProperty.set(target, mIntAnimatedValue);
822b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                return;
823b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            }
8246e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            if (mJniSetter != 0) {
8256e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                nCallIntMethod(target, mJniSetter, mIntAnimatedValue);
8266e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                return;
8276e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            }
8287c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            if (mSetter != null) {
8297c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                try {
8307c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    mTmpValueArray[0] = mIntAnimatedValue;
8317c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    mSetter.invoke(target, mTmpValueArray);
8327c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                } catch (InvocationTargetException e) {
8337c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    Log.e("PropertyValuesHolder", e.toString());
8347c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                } catch (IllegalAccessException e) {
8357c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    Log.e("PropertyValuesHolder", e.toString());
8367c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                }
8377c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            }
8387c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
8396e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase
8406e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase        @Override
8416e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase        void setupSetter(Class targetClass) {
842b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            if (mProperty != null) {
843b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                return;
844b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            }
8456e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            // Check new static hashmap<propName, int> for setter method
8466e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            try {
8476e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                mPropertyMapLock.writeLock().lock();
8486e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                HashMap<String, Integer> propertyMap = sJNISetterPropertyMap.get(targetClass);
8496e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                if (propertyMap != null) {
8506e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                    Integer mJniSetterInteger = propertyMap.get(mPropertyName);
8516e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                    if (mJniSetterInteger != null) {
8526e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                        mJniSetter = mJniSetterInteger;
8536e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                    }
8546e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                }
8556e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                if (mJniSetter == 0) {
8566e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                    String methodName = getMethodName("set", mPropertyName);
8576e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                    mJniSetter = nGetIntMethod(targetClass, methodName);
8586e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                    if (mJniSetter != 0) {
8596e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                        if (propertyMap == null) {
8606e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                            propertyMap = new HashMap<String, Integer>();
8616e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                            sJNISetterPropertyMap.put(targetClass, propertyMap);
8626e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                        }
8636e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                        propertyMap.put(mPropertyName, mJniSetter);
8646e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                    }
8656e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                }
8666e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            } catch (NoSuchMethodError e) {
867db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase                // Couldn't find it via JNI - try reflection next. Probably means the method
868db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase                // doesn't exist, or the type is wrong. An error will be logged later if
869db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase                // reflection fails as well.
8706e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            } finally {
8716e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                mPropertyMapLock.writeLock().unlock();
8726e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            }
8736e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            if (mJniSetter == 0) {
8746e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                // Couldn't find method through fast JNI approach - just use reflection
8756e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                super.setupSetter(targetClass);
8766e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            }
8776e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase        }
8787c608f25d494c8a0a671e7373efbb47ca635367eChet Haase    }
8797c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
8807c608f25d494c8a0a671e7373efbb47ca635367eChet Haase    static class FloatPropertyValuesHolder extends PropertyValuesHolder {
8817c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
882b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        // Cache JNI functions to avoid looking them up twice
8836e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase        private static final HashMap<Class, HashMap<String, Integer>> sJNISetterPropertyMap =
8846e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                new HashMap<Class, HashMap<String, Integer>>();
8856e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase        int mJniSetter;
886b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        private FloatProperty mFloatProperty;
8876e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase
8887c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        FloatKeyframeSet mFloatKeyframeSet;
8897c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        float mFloatAnimatedValue;
8907c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
8917c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        public FloatPropertyValuesHolder(String propertyName, FloatKeyframeSet keyframeSet) {
8927c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            super(propertyName);
8937c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            mValueType = float.class;
8947c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            mKeyframeSet = keyframeSet;
8957c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet;
8967c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
8977c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
898b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        public FloatPropertyValuesHolder(Property property, FloatKeyframeSet keyframeSet) {
899b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            super(property);
900b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            mValueType = float.class;
901b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            mKeyframeSet = keyframeSet;
902b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet;
903b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            if (property instanceof FloatProperty) {
904b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                mFloatProperty = (FloatProperty) mProperty;
905b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            }
906b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        }
907b39f051631250c49936a475d0e64584afb7f1b93Chet Haase
9087c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        public FloatPropertyValuesHolder(String propertyName, float... values) {
9097c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            super(propertyName);
9107c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            setFloatValues(values);
911691ac26817d489d9770aa6ba7b098ff17e8be99aChet Haase        }
912691ac26817d489d9770aa6ba7b098ff17e8be99aChet Haase
913b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        public FloatPropertyValuesHolder(Property property, float... values) {
914b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            super(property);
915b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            setFloatValues(values);
916b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            if (property instanceof  FloatProperty) {
917b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                mFloatProperty = (FloatProperty) mProperty;
918b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            }
919b39f051631250c49936a475d0e64584afb7f1b93Chet Haase        }
920b39f051631250c49936a475d0e64584afb7f1b93Chet Haase
921691ac26817d489d9770aa6ba7b098ff17e8be99aChet Haase        @Override
922691ac26817d489d9770aa6ba7b098ff17e8be99aChet Haase        public void setFloatValues(float... values) {
923691ac26817d489d9770aa6ba7b098ff17e8be99aChet Haase            super.setFloatValues(values);
9247c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet;
9257c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
9267c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
9277c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        @Override
9287c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        void calculateValue(float fraction) {
9297c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            mFloatAnimatedValue = mFloatKeyframeSet.getFloatValue(fraction);
9307c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
9317c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
9327c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        @Override
9337c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        Object getAnimatedValue() {
9347c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            return mFloatAnimatedValue;
9357c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
9367c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
9377c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        @Override
9387c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        public FloatPropertyValuesHolder clone() {
9397c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            FloatPropertyValuesHolder newPVH = (FloatPropertyValuesHolder) super.clone();
9407c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            newPVH.mFloatKeyframeSet = (FloatKeyframeSet) newPVH.mKeyframeSet;
9417c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            return newPVH;
9427c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
9437c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
9447c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        /**
9457c608f25d494c8a0a671e7373efbb47ca635367eChet Haase         * Internal function to set the value on the target object, using the setter set up
9467c608f25d494c8a0a671e7373efbb47ca635367eChet Haase         * earlier on this PropertyValuesHolder object. This function is called by ObjectAnimator
9477c608f25d494c8a0a671e7373efbb47ca635367eChet Haase         * to handle turning the value calculated by ValueAnimator into a value set on the object
9487c608f25d494c8a0a671e7373efbb47ca635367eChet Haase         * according to the name of the property.
9497c608f25d494c8a0a671e7373efbb47ca635367eChet Haase         * @param target The target object on which the value is set
9507c608f25d494c8a0a671e7373efbb47ca635367eChet Haase         */
9517c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        @Override
9527c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        void setAnimatedValue(Object target) {
953b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            if (mFloatProperty != null) {
954b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                mFloatProperty.setValue(target, mFloatAnimatedValue);
955b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                return;
956b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            }
957b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            if (mProperty != null) {
958b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                mProperty.set(target, mFloatAnimatedValue);
959b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                return;
960b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            }
9616e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            if (mJniSetter != 0) {
9626e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                nCallFloatMethod(target, mJniSetter, mFloatAnimatedValue);
9636e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                return;
9646e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            }
9657c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            if (mSetter != null) {
9667c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                try {
9677c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    mTmpValueArray[0] = mFloatAnimatedValue;
9687c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    mSetter.invoke(target, mTmpValueArray);
9697c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                } catch (InvocationTargetException e) {
9707c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    Log.e("PropertyValuesHolder", e.toString());
9717c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                } catch (IllegalAccessException e) {
9727c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    Log.e("PropertyValuesHolder", e.toString());
9737c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                }
9747c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            }
9757c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        }
9767c608f25d494c8a0a671e7373efbb47ca635367eChet Haase
9776e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase        @Override
9786e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase        void setupSetter(Class targetClass) {
979b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            if (mProperty != null) {
980b39f051631250c49936a475d0e64584afb7f1b93Chet Haase                return;
981b39f051631250c49936a475d0e64584afb7f1b93Chet Haase            }
9826e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            // Check new static hashmap<propName, int> for setter method
9836e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            try {
9846e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                mPropertyMapLock.writeLock().lock();
9856e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                HashMap<String, Integer> propertyMap = sJNISetterPropertyMap.get(targetClass);
9866e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                if (propertyMap != null) {
9876e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                    Integer mJniSetterInteger = propertyMap.get(mPropertyName);
9886e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                    if (mJniSetterInteger != null) {
9896e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                        mJniSetter = mJniSetterInteger;
9906e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                    }
9916e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                }
9926e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                if (mJniSetter == 0) {
9936e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                    String methodName = getMethodName("set", mPropertyName);
9946e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                    mJniSetter = nGetFloatMethod(targetClass, methodName);
9956e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                    if (mJniSetter != 0) {
9966e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                        if (propertyMap == null) {
9976e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                            propertyMap = new HashMap<String, Integer>();
9986e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                            sJNISetterPropertyMap.put(targetClass, propertyMap);
9996e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                        }
10006e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                        propertyMap.put(mPropertyName, mJniSetter);
10016e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                    }
10026e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                }
10036e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            } catch (NoSuchMethodError e) {
1004db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase                // Couldn't find it via JNI - try reflection next. Probably means the method
1005db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase                // doesn't exist, or the type is wrong. An error will be logged later if
1006db4101c7d5a2af174bdc61dc706329faabaeb5c6Chet Haase                // reflection fails as well.
10076e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            } finally {
10086e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                mPropertyMapLock.writeLock().unlock();
10096e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            }
10106e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            if (mJniSetter == 0) {
10116e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                // Couldn't find method through fast JNI approach - just use reflection
10126e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase                super.setupSetter(targetClass);
10136e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase            }
10146e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase        }
10156e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase
10167c608f25d494c8a0a671e7373efbb47ca635367eChet Haase    }
10176e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase
10186e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase    native static private int nGetIntMethod(Class targetClass, String methodName);
10196e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase    native static private int nGetFloatMethod(Class targetClass, String methodName);
10206e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase    native static private void nCallIntMethod(Object target, int methodID, int arg);
10216e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase    native static private void nCallFloatMethod(Object target, int methodID, float arg);
1022d953d08e9299072130d9f4411cbcf6678bbce822Chet Haase}