From b39f051631250c49936a475d0e64584afb7f1b93 Mon Sep 17 00:00:00 2001 From: Chet Haase Date: Tue, 24 May 2011 14:36:40 -0700 Subject: Add 'Property' object This change adds a generic Property facility to the SDK, which allows an easy way to reference fields (private or otherwise) in a general way. For example, animations can use this facility to animate 'properties' on target objects in a way that is more code- and compiler-friendly than the existing String-based approach (for objects which have implemented Properties, of course). The animator classes have been updated to use this new approach (in addition to Strings, which are still more generally useful for objects which have get/set functions but not Property objects). The change also includes new Property objects on View (which can now be used in creating animations on Views). There is an unrelated change on GLES20RecordingCanvas to change the way we cache bitmaps, which avoids spurious garbage by using an ArrayList instead of a HashSet. Change-Id: I167b43a3fca20e7695b1a23ca81274367539acda --- core/java/android/animation/FloatEvaluator.java | 8 +- core/java/android/animation/IntEvaluator.java | 8 +- core/java/android/animation/ObjectAnimator.java | 221 ++++++++++++++------- .../android/animation/PropertyValuesHolder.java | 213 +++++++++++++++++++- core/java/android/animation/TypeEvaluator.java | 4 +- 5 files changed, 363 insertions(+), 91 deletions(-) (limited to 'core/java/android/animation') diff --git a/core/java/android/animation/FloatEvaluator.java b/core/java/android/animation/FloatEvaluator.java index 9e2054d..9463aa1 100644 --- a/core/java/android/animation/FloatEvaluator.java +++ b/core/java/android/animation/FloatEvaluator.java @@ -19,7 +19,7 @@ package android.animation; /** * This evaluator can be used to perform type interpolation between float values. */ -public class FloatEvaluator implements TypeEvaluator { +public class FloatEvaluator implements TypeEvaluator { /** * This function returns the result of linearly interpolating the start and end values, with @@ -35,8 +35,8 @@ public class FloatEvaluator implements TypeEvaluator { * @return A linear interpolation between the start and end values, given the * fraction parameter. */ - public Object evaluate(float fraction, Object startValue, Object endValue) { - float startFloat = ((Number) startValue).floatValue(); - return startFloat + fraction * (((Number) endValue).floatValue() - startFloat); + public Float evaluate(float fraction, Number startValue, Number endValue) { + float startFloat = startValue.floatValue(); + return startFloat + fraction * (endValue.floatValue() - startFloat); } } \ No newline at end of file diff --git a/core/java/android/animation/IntEvaluator.java b/core/java/android/animation/IntEvaluator.java index 7288927..34fb0dc 100644 --- a/core/java/android/animation/IntEvaluator.java +++ b/core/java/android/animation/IntEvaluator.java @@ -19,7 +19,7 @@ package android.animation; /** * This evaluator can be used to perform type interpolation between int values. */ -public class IntEvaluator implements TypeEvaluator { +public class IntEvaluator implements TypeEvaluator { /** * This function returns the result of linearly interpolating the start and end values, with @@ -35,8 +35,8 @@ public class IntEvaluator implements TypeEvaluator { * @return A linear interpolation between the start and end values, given the * fraction parameter. */ - public Object evaluate(float fraction, Object startValue, Object endValue) { - int startInt = ((Number) startValue).intValue(); - return (int) (startInt + fraction * (((Number) endValue).intValue() - startInt)); + public Integer evaluate(float fraction, Integer startValue, Integer endValue) { + int startInt = startValue; + return (int)(startInt + fraction * (endValue - startInt)); } } \ No newline at end of file diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java index b8a7cb2..31c5f8d 100644 --- a/core/java/android/animation/ObjectAnimator.java +++ b/core/java/android/animation/ObjectAnimator.java @@ -17,6 +17,7 @@ package android.animation; import android.util.Log; +import android.util.Property; import java.lang.reflect.Method; import java.util.ArrayList; @@ -39,6 +40,8 @@ public final class ObjectAnimator extends ValueAnimator { private String mPropertyName; + private Property mProperty; + /** * Sets the name of the property that will be animated. This name is used to derive * a setter function that will be called to set animated values. @@ -63,7 +66,7 @@ public final class ObjectAnimator extends ValueAnimator { * using more than one PropertyValuesHolder objects, then setting the propertyName simply * sets the propertyName in the first of those PropertyValuesHolder objects.

* - * @param propertyName The name of the property being animated. + * @param propertyName The name of the property being animated. Should not be null. */ public void setPropertyName(String propertyName) { // mValues could be null if this is being constructed piecemeal. Just record the @@ -81,6 +84,31 @@ public final class ObjectAnimator extends ValueAnimator { } /** + * Sets the property that will be animated. Property objects will take precedence over + * properties specified by the {@link #setPropertyName(String)} method. Animations should + * be set up to use one or the other, not both. + * + * @param property The property being animated. Should not be null. + */ + public void setProperty(Property property) { + // mValues could be null if this is being constructed piecemeal. Just record the + // propertyName to be used later when setValues() is called if so. + if (mValues != null) { + PropertyValuesHolder valuesHolder = mValues[0]; + String oldName = valuesHolder.getPropertyName(); + valuesHolder.setProperty(property); + mValuesMap.remove(oldName); + mValuesMap.put(mPropertyName, valuesHolder); + } + if (mProperty != null) { + mPropertyName = property.getName(); + } + mProperty = property; + // New property/values/target should cause re-initialization prior to starting + mInitialized = false; + } + + /** * Gets the name of the property that will be animated. This name will be used to derive * a setter function that will be called to set animated values. * For example, a property name of foo will result @@ -93,36 +121,6 @@ public final class ObjectAnimator extends ValueAnimator { } /** - * Determine the setter or getter function using the JavaBeans convention of setFoo or - * getFoo for a property named 'foo'. This function figures out what the name of the - * function should be and uses reflection to find the Method with that name on the - * target object. - * - * @param prefix "set" or "get", depending on whether we need a setter or getter. - * @return Method the method associated with mPropertyName. - */ - private Method getPropertyFunction(String prefix, Class valueType) { - // TODO: faster implementation... - Method returnVal = null; - String firstLetter = mPropertyName.substring(0, 1); - String theRest = mPropertyName.substring(1); - firstLetter = firstLetter.toUpperCase(); - String setterName = prefix + firstLetter + theRest; - Class args[] = null; - if (valueType != null) { - args = new Class[1]; - args[0] = valueType; - } - try { - returnVal = mTarget.getClass().getMethod(setterName, args); - } catch (NoSuchMethodException e) { - Log.e("ObjectAnimator", - "Couldn't find setter/getter for property " + mPropertyName + ": " + e); - } - return returnVal; - } - - /** * Creates a new ObjectAnimator object. This default constructor is primarily for * use internally; the other constructors which take parameters are more generally * useful. @@ -131,8 +129,8 @@ public final class ObjectAnimator extends ValueAnimator { } /** - * A constructor that takes a single property name and set of values. This constructor is - * used in the simple case of animating a single property. + * Private utility constructor that initializes the target object and name of the + * property being animated. * * @param target The object whose property is to be animated. This object should * have a public method on it called setName(), where name is @@ -145,19 +143,29 @@ public final class ObjectAnimator extends ValueAnimator { } /** + * Private utility constructor that initializes the target object and property being animated. + * + * @param target The object whose property is to be animated. + * @param property The property being animated. + */ + private ObjectAnimator(T target, Property property) { + mTarget = target; + setProperty(property); + } + + /** * Constructs and returns an ObjectAnimator that animates between int values. A single - * value implies that that value is the one being animated to. However, this is not typically - * useful in a ValueAnimator object because there is no way for the object to determine the - * starting value for the animation (unlike ObjectAnimator, which can derive that value - * from the target object and property being animated). Therefore, there should typically - * be two or more values. + * value implies that that value is the one being animated to. Two values imply a starting + * and ending values. More than two values imply a starting value, values to animate through + * along the way, and an ending value (these values will be distributed evenly across + * the duration of the animation). * * @param target The object whose property is to be animated. This object should * have a public method on it called setName(), where name is * the value of the propertyName parameter. * @param propertyName The name of the property being animated. * @param values A set of values that the animation will animate between over time. - * @return A ValueAnimator object that is set up to animate between the given values. + * @return An ObjectAnimator object that is set up to animate between the given values. */ public static ObjectAnimator ofInt(Object target, String propertyName, int... values) { ObjectAnimator anim = new ObjectAnimator(target, propertyName); @@ -166,19 +174,36 @@ public final class ObjectAnimator extends ValueAnimator { } /** + * Constructs and returns an ObjectAnimator that animates between int values. A single + * value implies that that value is the one being animated to. Two values imply a starting + * and ending values. More than two values imply a starting value, values to animate through + * along the way, and an ending value (these values will be distributed evenly across + * the duration of the animation). + * + * @param target The object whose property is to be animated. + * @param property The property being animated. + * @param values A set of values that the animation will animate between over time. + * @return An ObjectAnimator object that is set up to animate between the given values. + */ + public static ObjectAnimator ofInt(T target, Property property, int... values) { + ObjectAnimator anim = new ObjectAnimator(target, property); + anim.setIntValues(values); + return anim; + } + + /** * Constructs and returns an ObjectAnimator that animates between float values. A single - * value implies that that value is the one being animated to. However, this is not typically - * useful in a ValueAnimator object because there is no way for the object to determine the - * starting value for the animation (unlike ObjectAnimator, which can derive that value - * from the target object and property being animated). Therefore, there should typically - * be two or more values. + * value implies that that value is the one being animated to. Two values imply a starting + * and ending values. More than two values imply a starting value, values to animate through + * along the way, and an ending value (these values will be distributed evenly across + * the duration of the animation). * * @param target The object whose property is to be animated. This object should * have a public method on it called setName(), where name is * the value of the propertyName parameter. * @param propertyName The name of the property being animated. * @param values A set of values that the animation will animate between over time. - * @return A ValueAnimator object that is set up to animate between the given values. + * @return An ObjectAnimator object that is set up to animate between the given values. */ public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) { ObjectAnimator anim = new ObjectAnimator(target, propertyName); @@ -187,21 +212,40 @@ public final class ObjectAnimator extends ValueAnimator { } /** - * A constructor that takes PropertyValueHolder values. This constructor should - * be used when animating several properties at once with the same ObjectAnimator, since - * PropertyValuesHolder allows you to associate a set of animation values with a property - * name. + * Constructs and returns an ObjectAnimator that animates between float values. A single + * value implies that that value is the one being animated to. Two values imply a starting + * and ending values. More than two values imply a starting value, values to animate through + * along the way, and an ending value (these values will be distributed evenly across + * the duration of the animation). + * + * @param target The object whose property is to be animated. + * @param property The property being animated. + * @param values A set of values that the animation will animate between over time. + * @return An ObjectAnimator object that is set up to animate between the given values. + */ + public static ObjectAnimator ofFloat(T target, Property property, + float... values) { + ObjectAnimator anim = new ObjectAnimator(target, property); + anim.setFloatValues(values); + return anim; + } + + /** + * Constructs and returns an ObjectAnimator that animates between Object values. A single + * value implies that that value is the one being animated to. Two values imply a starting + * and ending values. More than two values imply a starting value, values to animate through + * along the way, and an ending value (these values will be distributed evenly across + * the duration of the animation). * * @param target The object whose property is to be animated. This object should - * have public methods on it called setName(), where name is - * the name of the property passed in as the propertyName parameter for - * each of the PropertyValuesHolder objects. + * have a public method on it called setName(), where name is + * the value of the propertyName parameter. * @param propertyName The name of the property being animated. * @param evaluator A TypeEvaluator that will be called on each animation frame to - * provide the ncessry interpolation between the Object values to derive the animated + * provide the necessary interpolation between the Object values to derive the animated * value. - * @param values The PropertyValuesHolder objects which hold each the property name and values - * to animate that property between. + * @param values A set of values that the animation will animate between over time. + * @return An ObjectAnimator object that is set up to animate between the given values. */ public static ObjectAnimator ofObject(Object target, String propertyName, TypeEvaluator evaluator, Object... values) { @@ -212,19 +256,44 @@ public final class ObjectAnimator extends ValueAnimator { } /** - * Constructs and returns an ObjectAnimator that animates between the sets of values - * specifed in PropertyValueHolder objects. This variant should - * be used when animating several properties at once with the same ObjectAnimator, since - * PropertyValuesHolder allows you to associate a set of animation values with a property - * name. + * Constructs and returns an ObjectAnimator that animates between Object values. A single + * value implies that that value is the one being animated to. Two values imply a starting + * and ending values. More than two values imply a starting value, values to animate through + * along the way, and an ending value (these values will be distributed evenly across + * the duration of the animation). * - * @param target The object whose property is to be animated. This object should - * have public methods on it called setName(), where name is - * the name of the property passed in as the propertyName parameter for - * each of the PropertyValuesHolder objects. - * @param values A set of PropertyValuesHolder objects whose values will be animated - * between over time. - * @return A ValueAnimator object that is set up to animate between the given values. + * @param target The object whose property is to be animated. + * @param property The property being animated. + * @param evaluator A TypeEvaluator that will be called on each animation frame to + * provide the necessary interpolation between the Object values to derive the animated + * value. + * @param values A set of values that the animation will animate between over time. + * @return An ObjectAnimator object that is set up to animate between the given values. + */ + public static ObjectAnimator ofObject(T target, Property property, + TypeEvaluator evaluator, V... values) { + ObjectAnimator anim = new ObjectAnimator(target, property); + anim.setObjectValues(values); + anim.setEvaluator(evaluator); + return anim; + } + + /** + * Constructs and returns an ObjectAnimator that animates between the sets of values specified + * in PropertyValueHolder objects. This variant should be used when animating + * several properties at once with the same ObjectAnimator, since PropertyValuesHolder allows + * you to associate a set of animation values with a property name. + * + * @param target The object whose property is to be animated. Depending on how the + * PropertyValuesObjects were constructed, the target object should either have the {@link + * android.util.Property} objects used to construct the PropertyValuesHolder objects or (if the + * PropertyValuesHOlder objects were created with property names) the target object should have + * public methods on it called setName(), where name is the name of + * the property passed in as the propertyName parameter for each of the + * PropertyValuesHolder objects. + * @param values A set of PropertyValuesHolder objects whose values will be animated between + * over time. + * @return An ObjectAnimator object that is set up to animate between the given values. */ public static ObjectAnimator ofPropertyValuesHolder(Object target, PropertyValuesHolder... values) { @@ -239,7 +308,11 @@ public final class ObjectAnimator extends ValueAnimator { if (mValues == null || mValues.length == 0) { // No values yet - this animator is being constructed piecemeal. Init the values with // whatever the current propertyName is - setValues(PropertyValuesHolder.ofInt(mPropertyName, values)); + if (mProperty != null) { + setValues(PropertyValuesHolder.ofInt(mProperty, values)); + } else { + setValues(PropertyValuesHolder.ofInt(mPropertyName, values)); + } } else { super.setIntValues(values); } @@ -250,7 +323,11 @@ public final class ObjectAnimator extends ValueAnimator { if (mValues == null || mValues.length == 0) { // No values yet - this animator is being constructed piecemeal. Init the values with // whatever the current propertyName is - setValues(PropertyValuesHolder.ofFloat(mPropertyName, values)); + if (mProperty != null) { + setValues(PropertyValuesHolder.ofFloat(mProperty, values)); + } else { + setValues(PropertyValuesHolder.ofFloat(mPropertyName, values)); + } } else { super.setFloatValues(values); } @@ -261,7 +338,11 @@ public final class ObjectAnimator extends ValueAnimator { if (mValues == null || mValues.length == 0) { // No values yet - this animator is being constructed piecemeal. Init the values with // whatever the current propertyName is - setValues(PropertyValuesHolder.ofObject(mPropertyName, (TypeEvaluator)null, values)); + if (mProperty != null) { + setValues(PropertyValuesHolder.ofObject(mProperty, (TypeEvaluator)null, values)); + } else { + setValues(PropertyValuesHolder.ofObject(mPropertyName, (TypeEvaluator)null, values)); + } } else { super.setObjectValues(values); } diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java index 6f91fc0..58f23f7 100644 --- a/core/java/android/animation/PropertyValuesHolder.java +++ b/core/java/android/animation/PropertyValuesHolder.java @@ -16,7 +16,10 @@ package android.animation; +import android.util.FloatProperty; +import android.util.IntProperty; import android.util.Log; +import android.util.Property; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -39,6 +42,11 @@ public class PropertyValuesHolder implements Cloneable { String mPropertyName; /** + * @hide + */ + protected Property mProperty; + + /** * The setter function, if needed. ObjectAnimator hands off this functionality to * PropertyValuesHolder, since it holds all of the per-property information. This * property is automatically @@ -124,6 +132,17 @@ public class PropertyValuesHolder implements Cloneable { } /** + * Internal utility constructor, used by the factory methods to set the property. + * @param property The property for this holder. + */ + private PropertyValuesHolder(Property property) { + mProperty = property; + if (property != null) { + mPropertyName = property.getName(); + } + } + + /** * Constructs and returns a PropertyValuesHolder with a given property name and * set of int values. * @param propertyName The name of the property being animated. @@ -131,8 +150,18 @@ public class PropertyValuesHolder implements Cloneable { * @return PropertyValuesHolder The constructed PropertyValuesHolder object. */ public static PropertyValuesHolder ofInt(String propertyName, int... values) { - PropertyValuesHolder pvh = new IntPropertyValuesHolder(propertyName, values); - return pvh; + return new IntPropertyValuesHolder(propertyName, values); + } + + /** + * Constructs and returns a PropertyValuesHolder with a given property and + * set of int values. + * @param property The property being animated. Should not be null. + * @param values The values that the property will animate between. + * @return PropertyValuesHolder The constructed PropertyValuesHolder object. + */ + public static PropertyValuesHolder ofInt(Property property, int... values) { + return new IntPropertyValuesHolder(property, values); } /** @@ -143,18 +172,28 @@ public class PropertyValuesHolder implements Cloneable { * @return PropertyValuesHolder The constructed PropertyValuesHolder object. */ public static PropertyValuesHolder ofFloat(String propertyName, float... values) { - PropertyValuesHolder pvh = new FloatPropertyValuesHolder(propertyName, values); - return pvh; + return new FloatPropertyValuesHolder(propertyName, values); + } + + /** + * Constructs and returns a PropertyValuesHolder with a given property and + * set of float values. + * @param property The property being animated. Should not be null. + * @param values The values that the property will animate between. + * @return PropertyValuesHolder The constructed PropertyValuesHolder object. + */ + public static PropertyValuesHolder ofFloat(Property property, float... values) { + return new FloatPropertyValuesHolder(property, values); } /** * Constructs and returns a PropertyValuesHolder with a given property name and * set of Object values. This variant also takes a TypeEvaluator because the system - * cannot interpolate between objects of unknown type. + * cannot automatically interpolate between objects of unknown type. * * @param propertyName The name of the property being animated. * @param evaluator A TypeEvaluator that will be called on each animation frame to - * provide the ncessry interpolation between the Object values to derive the animated + * provide the necessary interpolation between the Object values to derive the animated * value. * @param values The values that the named property will animate between. * @return PropertyValuesHolder The constructed PropertyValuesHolder object. @@ -168,6 +207,26 @@ public class PropertyValuesHolder implements Cloneable { } /** + * Constructs and returns a PropertyValuesHolder with a given property and + * set of Object values. This variant also takes a TypeEvaluator because the system + * cannot automatically interpolate between objects of unknown type. + * + * @param property The property being animated. Should not be null. + * @param evaluator A TypeEvaluator that will be called on each animation frame to + * provide the necessary interpolation between the Object values to derive the animated + * value. + * @param values The values that the property will animate between. + * @return PropertyValuesHolder The constructed PropertyValuesHolder object. + */ + public static PropertyValuesHolder ofObject(Property property, + TypeEvaluator evaluator, V... values) { + PropertyValuesHolder pvh = new PropertyValuesHolder(property); + pvh.setObjectValues(values); + pvh.setEvaluator(evaluator); + return pvh; + } + + /** * Constructs and returns a PropertyValuesHolder object with the specified property name and set * of values. These values can be of any type, but the type should be consistent so that * an appropriate {@link android.animation.TypeEvaluator} can be found that matches @@ -202,6 +261,37 @@ public class PropertyValuesHolder implements Cloneable { } /** + * Constructs and returns a PropertyValuesHolder object with the specified property and set + * of values. These values can be of any type, but the type should be consistent so that + * an appropriate {@link android.animation.TypeEvaluator} can be found that matches + * the common type. + *

If there is only one value, it is assumed to be the end value of an animation, + * and an initial value will be derived, if possible, by calling the property's + * {@link android.util.Property#get(Object)} function. + * Also, if any value is null, the value will be filled in when the animation + * starts in the same way. This mechanism of automatically getting null values only works + * if the PropertyValuesHolder object is used in conjunction with + * {@link ObjectAnimator}, since otherwise PropertyValuesHolder has + * no way of determining what the value should be. + * @param property The property associated with this set of values. Should not be null. + * @param values The set of values to animate between. + */ + public static PropertyValuesHolder ofKeyframe(Property property, Keyframe... values) { + KeyframeSet keyframeSet = KeyframeSet.ofKeyframe(values); + if (keyframeSet instanceof IntKeyframeSet) { + return new IntPropertyValuesHolder(property, (IntKeyframeSet) keyframeSet); + } else if (keyframeSet instanceof FloatKeyframeSet) { + return new FloatPropertyValuesHolder(property, (FloatKeyframeSet) keyframeSet); + } + else { + PropertyValuesHolder pvh = new PropertyValuesHolder(property); + pvh.mKeyframeSet = keyframeSet; + pvh.mValueType = ((Keyframe)values[0]).getType(); + return pvh; + } + } + + /** * Set the animated values for this object to this set of ints. * If there is only one value, it is assumed to be the end value of an animation, * and an initial value will be derived, if possible, by calling a getter function @@ -349,7 +439,6 @@ public class PropertyValuesHolder implements Cloneable { // Have to lock property map prior to reading it, to guard against // another thread putting something in there after we've checked it // but before we've added an entry to it - // TODO: can we store the setter/getter per Class instead of per Object? mPropertyMapLock.writeLock().lock(); HashMap propertyMap = propertyMapMap.get(targetClass); if (propertyMap != null) { @@ -395,6 +484,22 @@ public class PropertyValuesHolder implements Cloneable { * @param target The object on which the setter (and possibly getter) exist. */ void setupSetterAndGetter(Object target) { + if (mProperty != null) { + // check to make sure that mProperty is on the class of target + try { + Object testValue = mProperty.get(target); + for (Keyframe kf : mKeyframeSet.mKeyframes) { + if (!kf.hasValue()) { + kf.setValue(mProperty.get(target)); + } + } + return; + } catch (ClassCastException e) { + Log.e("PropertyValuesHolder","No such property (" + mProperty.getName() + + ") on target object " + target + ". Trying reflection instead"); + mProperty = null; + } + } Class targetClass = target.getClass(); if (mSetter == null) { setupSetter(targetClass); @@ -423,6 +528,9 @@ public class PropertyValuesHolder implements Cloneable { * @param kf The keyframe which holds the property name and value. */ private void setupValue(Object target, Keyframe kf) { + if (mProperty != null) { + kf.setValue(mProperty.get(target)); + } try { if (mGetter == null) { Class targetClass = target.getClass(); @@ -465,6 +573,7 @@ public class PropertyValuesHolder implements Cloneable { try { PropertyValuesHolder newPVH = (PropertyValuesHolder) super.clone(); newPVH.mPropertyName = mPropertyName; + newPVH.mProperty = mProperty; newPVH.mKeyframeSet = mKeyframeSet.clone(); newPVH.mEvaluator = mEvaluator; return newPVH; @@ -482,6 +591,9 @@ public class PropertyValuesHolder implements Cloneable { * @param target The target object on which the value is set */ void setAnimatedValue(Object target) { + if (mProperty != null) { + mProperty.set(target, getAnimatedValue()); + } if (mSetter != null) { try { mTmpValueArray[0] = getAnimatedValue(); @@ -558,6 +670,18 @@ public class PropertyValuesHolder implements Cloneable { } /** + * Sets the property that will be animated. + * + *

Note that if this PropertyValuesHolder object is used with ObjectAnimator, the property + * must exist on the target object specified in that ObjectAnimator.

+ * + * @param property The property being animated. + */ + public void setProperty(Property property) { + mProperty = property; + } + + /** * Gets the name of the property that will be animated. This name will be used to derive * a setter function that will be called to set animated values. * For example, a property name of foo will result @@ -597,17 +721,22 @@ public class PropertyValuesHolder implements Cloneable { * specified above. */ static String getMethodName(String prefix, String propertyName) { - char firstLetter = propertyName.charAt(0); + if (propertyName == null || propertyName.length() == 0) { + // shouldn't get here + return prefix; + } + char firstLetter = Character.toUpperCase(propertyName.charAt(0)); String theRest = propertyName.substring(1); - firstLetter = Character.toUpperCase(firstLetter); return prefix + firstLetter + theRest; } static class IntPropertyValuesHolder extends PropertyValuesHolder { + // Cache JNI functions to avoid looking them up twice private static final HashMap> sJNISetterPropertyMap = new HashMap>(); int mJniSetter; + private IntProperty mIntProperty; IntKeyframeSet mIntKeyframeSet; int mIntAnimatedValue; @@ -619,11 +748,29 @@ public class PropertyValuesHolder implements Cloneable { mIntKeyframeSet = (IntKeyframeSet) mKeyframeSet; } + public IntPropertyValuesHolder(Property property, IntKeyframeSet keyframeSet) { + super(property); + mValueType = int.class; + mKeyframeSet = keyframeSet; + mIntKeyframeSet = (IntKeyframeSet) mKeyframeSet; + if (property instanceof IntProperty) { + mIntProperty = (IntProperty) mProperty; + } + } + public IntPropertyValuesHolder(String propertyName, int... values) { super(propertyName); setIntValues(values); } + public IntPropertyValuesHolder(Property property, int... values) { + super(property); + setIntValues(values); + if (property instanceof IntProperty) { + mIntProperty = (IntProperty) mProperty; + } + } + @Override public void setIntValues(int... values) { super.setIntValues(values); @@ -656,6 +803,14 @@ public class PropertyValuesHolder implements Cloneable { */ @Override void setAnimatedValue(Object target) { + if (mIntProperty != null) { + mIntProperty.setValue(target, mIntAnimatedValue); + return; + } + if (mProperty != null) { + mProperty.set(target, mIntAnimatedValue); + return; + } if (mJniSetter != 0) { nCallIntMethod(target, mJniSetter, mIntAnimatedValue); return; @@ -674,6 +829,9 @@ public class PropertyValuesHolder implements Cloneable { @Override void setupSetter(Class targetClass) { + if (mProperty != null) { + return; + } // Check new static hashmap for setter method try { mPropertyMapLock.writeLock().lock(); @@ -696,7 +854,8 @@ public class PropertyValuesHolder implements Cloneable { } } } catch (NoSuchMethodError e) { - // System.out.println("Can't find native method using JNI, use reflection" + e); + Log.d("PropertyValuesHolder", + "Can't find native method using JNI, use reflection" + e); } finally { mPropertyMapLock.writeLock().unlock(); } @@ -709,9 +868,11 @@ public class PropertyValuesHolder implements Cloneable { static class FloatPropertyValuesHolder extends PropertyValuesHolder { + // Cache JNI functions to avoid looking them up twice private static final HashMap> sJNISetterPropertyMap = new HashMap>(); int mJniSetter; + private FloatProperty mFloatProperty; FloatKeyframeSet mFloatKeyframeSet; float mFloatAnimatedValue; @@ -723,11 +884,29 @@ public class PropertyValuesHolder implements Cloneable { mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet; } + public FloatPropertyValuesHolder(Property property, FloatKeyframeSet keyframeSet) { + super(property); + mValueType = float.class; + mKeyframeSet = keyframeSet; + mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet; + if (property instanceof FloatProperty) { + mFloatProperty = (FloatProperty) mProperty; + } + } + public FloatPropertyValuesHolder(String propertyName, float... values) { super(propertyName); setFloatValues(values); } + public FloatPropertyValuesHolder(Property property, float... values) { + super(property); + setFloatValues(values); + if (property instanceof FloatProperty) { + mFloatProperty = (FloatProperty) mProperty; + } + } + @Override public void setFloatValues(float... values) { super.setFloatValues(values); @@ -760,6 +939,14 @@ public class PropertyValuesHolder implements Cloneable { */ @Override void setAnimatedValue(Object target) { + if (mFloatProperty != null) { + mFloatProperty.setValue(target, mFloatAnimatedValue); + return; + } + if (mProperty != null) { + mProperty.set(target, mFloatAnimatedValue); + return; + } if (mJniSetter != 0) { nCallFloatMethod(target, mJniSetter, mFloatAnimatedValue); return; @@ -778,6 +965,9 @@ public class PropertyValuesHolder implements Cloneable { @Override void setupSetter(Class targetClass) { + if (mProperty != null) { + return; + } // Check new static hashmap for setter method try { mPropertyMapLock.writeLock().lock(); @@ -800,7 +990,8 @@ public class PropertyValuesHolder implements Cloneable { } } } catch (NoSuchMethodError e) { - // System.out.println("Can't find native method using JNI, use reflection" + e); + Log.d("PropertyValuesHolder", + "Can't find native method using JNI, use reflection" + e); } finally { mPropertyMapLock.writeLock().unlock(); } diff --git a/core/java/android/animation/TypeEvaluator.java b/core/java/android/animation/TypeEvaluator.java index fa49175..e738da1 100644 --- a/core/java/android/animation/TypeEvaluator.java +++ b/core/java/android/animation/TypeEvaluator.java @@ -24,7 +24,7 @@ package android.animation; * * @see ValueAnimator#setEvaluator(TypeEvaluator) */ -public interface TypeEvaluator { +public interface TypeEvaluator { /** * This function returns the result of linearly interpolating the start and end values, with @@ -39,6 +39,6 @@ public interface TypeEvaluator { * @return A linear interpolation between the start and end values, given the * fraction parameter. */ - public Object evaluate(float fraction, Object startValue, Object endValue); + public T evaluate(float fraction, T startValue, T endValue); } \ No newline at end of file -- cgit v1.1