summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorChet Haase <chet@google.com>2011-06-08 12:51:06 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2011-06-08 12:51:06 -0700
commitb19fcf3e9c6b9c8c2885b9ac7f7f836a0e2d6d22 (patch)
treee4eaf3e1713caf35bdaca546416453ba02ff8835 /core
parent608a23a07e6b9f7690e3dea0fff87408c6836308 (diff)
parentb39f051631250c49936a475d0e64584afb7f1b93 (diff)
downloadframeworks_base-b19fcf3e9c6b9c8c2885b9ac7f7f836a0e2d6d22.zip
frameworks_base-b19fcf3e9c6b9c8c2885b9ac7f7f836a0e2d6d22.tar.gz
frameworks_base-b19fcf3e9c6b9c8c2885b9ac7f7f836a0e2d6d22.tar.bz2
Merge "Add 'Property' object"
Diffstat (limited to 'core')
-rw-r--r--core/java/android/animation/FloatEvaluator.java8
-rw-r--r--core/java/android/animation/IntEvaluator.java8
-rw-r--r--core/java/android/animation/ObjectAnimator.java221
-rw-r--r--core/java/android/animation/PropertyValuesHolder.java213
-rw-r--r--core/java/android/animation/TypeEvaluator.java4
-rw-r--r--core/java/android/util/FloatProperty.java48
-rw-r--r--core/java/android/util/IntProperty.java48
-rw-r--r--core/java/android/util/NoSuchPropertyException.java30
-rw-r--r--core/java/android/util/Property.java106
-rw-r--r--core/java/android/util/ReflectiveProperty.java163
-rw-r--r--core/java/android/view/GLES20RecordingCanvas.java4
-rw-r--r--core/java/android/view/View.java165
12 files changed, 925 insertions, 93 deletions
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 <code>float</code> values.
*/
-public class FloatEvaluator implements TypeEvaluator {
+public class FloatEvaluator implements TypeEvaluator<Number> {
/**
* 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
* <code>fraction</code> 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 <code>int</code> values.
*/
-public class IntEvaluator implements TypeEvaluator {
+public class IntEvaluator implements TypeEvaluator<Integer> {
/**
* 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
* <code>fraction</code> 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.</p>
*
- * @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 <code>foo</code> 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 <code>setName()</code>, where <code>name</code> 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 <T> ObjectAnimator(T target, Property<T, ?> 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 <code>setName()</code>, where <code>name</code> is
* the value of the <code>propertyName</code> 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 <T> ObjectAnimator ofInt(T target, Property<T, Integer> 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 <code>setName()</code>, where <code>name</code> is
* the value of the <code>propertyName</code> 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 <code>PropertyValueHolder</code> 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 <T> ObjectAnimator ofFloat(T target, Property<T, Float> 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 <code>setName()</code>, where <code>name</code> is
- * the name of the property passed in as the <code>propertyName</code> parameter for
- * each of the PropertyValuesHolder objects.
+ * have a public method on it called <code>setName()</code>, where <code>name</code> is
+ * the value of the <code>propertyName</code> 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 <code>PropertyValueHolder</code> 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 <code>setName()</code>, where <code>name</code> is
- * the name of the property passed in as the <code>propertyName</code> 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 <T, V> ObjectAnimator ofObject(T target, Property<T, V> property,
+ TypeEvaluator<V> 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 <code>PropertyValueHolder</code> 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 <code>setName()</code>, where <code>name</code> is the name of
+ * the property passed in as the <code>propertyName</code> 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<?, Integer> 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<?, Float> 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 <V> PropertyValuesHolder ofObject(Property property,
+ TypeEvaluator<V> 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.
+ * <p>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<String, Method> 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.
+ *
+ * <p>Note that if this PropertyValuesHolder object is used with ObjectAnimator, the property
+ * must exist on the target object specified in that ObjectAnimator.</p>
+ *
+ * @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 <code>foo</code> 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<Class, HashMap<String, Integer>> sJNISetterPropertyMap =
new HashMap<Class, HashMap<String, Integer>>();
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<propName, int> 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<Class, HashMap<String, Integer>> sJNISetterPropertyMap =
new HashMap<Class, HashMap<String, Integer>>();
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<propName, int> 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<T> {
/**
* 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
* <code>fraction</code> 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
diff --git a/core/java/android/util/FloatProperty.java b/core/java/android/util/FloatProperty.java
new file mode 100644
index 0000000..a67b3cb
--- /dev/null
+++ b/core/java/android/util/FloatProperty.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.util;
+
+import android.util.Property;
+
+/**
+ * An implementation of {@link android.util.Property} to be used specifically with fields of type
+ * <code>float</code>. This type-specific subclass enables performance benefit by allowing
+ * calls to a {@link #set(Object, Float) set()} function that takes the primitive
+ * <code>float</code> type and avoids autoboxing and other overhead associated with the
+ * <code>Float</code> class.
+ *
+ * @param <T> The class on which the Property is declared.
+ *
+ * @hide
+ */
+public abstract class FloatProperty<T> extends Property<T, Float> {
+
+ public FloatProperty(String name) {
+ super(Float.class, name);
+ }
+
+ /**
+ * A type-specific override of the {@link #set(Object, Float)} that is faster when dealing
+ * with fields of type <code>float</code>.
+ */
+ public abstract void setValue(T object, float value);
+
+ @Override
+ final public void set(T object, Float value) {
+ setValue(object, value);
+ }
+
+} \ No newline at end of file
diff --git a/core/java/android/util/IntProperty.java b/core/java/android/util/IntProperty.java
new file mode 100644
index 0000000..459d6b2
--- /dev/null
+++ b/core/java/android/util/IntProperty.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.util;
+
+import android.util.Property;
+
+/**
+ * An implementation of {@link android.util.Property} to be used specifically with fields of type
+ * <code>int</code>. This type-specific subclass enables performance benefit by allowing
+ * calls to a {@link #set(Object, Integer) set()} function that takes the primitive
+ * <code>int</code> type and avoids autoboxing and other overhead associated with the
+ * <code>Integer</code> class.
+ *
+ * @param <T> The class on which the Property is declared.
+ *
+ * @hide
+ */
+public abstract class IntProperty<T> extends Property<T, Integer> {
+
+ public IntProperty(String name) {
+ super(Integer.class, name);
+ }
+
+ /**
+ * A type-specific override of the {@link #set(Object, Integer)} that is faster when dealing
+ * with fields of type <code>int</code>.
+ */
+ public abstract void setValue(T object, int value);
+
+ @Override
+ final public void set(T object, Integer value) {
+ set(object, value.intValue());
+ }
+
+} \ No newline at end of file
diff --git a/core/java/android/util/NoSuchPropertyException.java b/core/java/android/util/NoSuchPropertyException.java
new file mode 100644
index 0000000..b93f983
--- /dev/null
+++ b/core/java/android/util/NoSuchPropertyException.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.util;
+
+/**
+ * Thrown when code requests a {@link Property} on a class that does
+ * not expose the appropriate method or field.
+ *
+ * @see Property#of(java.lang.Class, java.lang.Class, java.lang.String)
+ */
+public class NoSuchPropertyException extends RuntimeException {
+
+ public NoSuchPropertyException(String s) {
+ super(s);
+ }
+
+}
diff --git a/core/java/android/util/Property.java b/core/java/android/util/Property.java
new file mode 100644
index 0000000..458e4c3
--- /dev/null
+++ b/core/java/android/util/Property.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.util;
+
+
+/**
+ * A property is an abstraction that can be used to represent a <emb>mutable</em> value that is held
+ * in a <em>host</em> object. The Property's {@link #set(Object, Object)} or {@link #get(Object)}
+ * methods can be implemented in terms of the private fields of the host object, or via "setter" and
+ * "getter" methods or by some other mechanism, as appropriate.
+ *
+ * @param <T> The class on which the property is declared.
+ * @param <V> The type that this property represents.
+ */
+public abstract class Property<T, V> {
+
+ private final String mName;
+ private final Class<V> mType;
+
+ /**
+ * This factory method creates and returns a Property given the <code>class</code> and
+ * <code>name</code> parameters, where the <code>"name"</code> parameter represents either:
+ * <ul>
+ * <li>a public <code>getName()</code> method on the class which takes no arguments, plus an
+ * optional public <code>setName()</code> method which takes a value of the same type
+ * returned by <code>getName()</code>
+ * <li>a public <code>isName()</code> method on the class which takes no arguments, plus an
+ * optional public <code>setName()</code> method which takes a value of the same type
+ * returned by <code>isName()</code>
+ * <li>a public <code>name</code> field on the class
+ * </ul>
+ *
+ * <p>If either of the get/is method alternatives is found on the class, but an appropriate
+ * <code>setName()</code> method is not found, the <code>Property</code> will be
+ * {@link #isReadOnly() readOnly}. Calling the {@link #set(Object, Object)} method on such
+ * a property is allowed, but will have no effect.</p>
+ *
+ * <p>If neither the methods nor the field are found on the class a
+ * {@link NoSuchPropertyException} exception will be thrown.</p>
+ */
+ public static <T, V> Property<T, V> of(Class<T> hostType, Class<V> valueType, String name) {
+ return new ReflectiveProperty<T, V>(hostType, valueType, name);
+ }
+
+ /**
+ * A constructor that takes an identifying name and {@link #getType() type} for the property.
+ */
+ public Property(Class<V> type, String name) {
+ mName = name;
+ mType = type;
+ }
+
+ /**
+ * Returns true if the {@link #set(Object, Object)} method does not set the value on the target
+ * object (in which case the {@link #set(Object, Object) set()} method should throw a {@link
+ * NoSuchPropertyException} exception). This may happen if the Property wraps functionality that
+ * allows querying the underlying value but not setting it. For example, the {@link #of(Class,
+ * Class, String)} factory method may return a Property with name "foo" for an object that has
+ * only a <code>getFoo()</code> or <code>isFoo()</code> method, but no matching
+ * <code>setFoo()</code> method.
+ */
+ public boolean isReadOnly() {
+ return false;
+ }
+
+ /**
+ * Sets the value on <code>object</code> which this property represents. If the method is unable
+ * to set the value on the target object, it will throw a {@link NoSuchPropertyException}
+ * exception.
+ */
+ public void set(T object, V value) {
+ throw new NoSuchPropertyException("Property is read-only; set() is not implemented");
+ }
+
+ /**
+ * Returns the current value that this property represents on the given <code>object</code>.
+ */
+ public abstract V get(T object);
+
+ /**
+ * Returns the name for this property.
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * Returns the type for this property.
+ */
+ public Class<V> getType() {
+ return mType;
+ }
+}
diff --git a/core/java/android/util/ReflectiveProperty.java b/core/java/android/util/ReflectiveProperty.java
new file mode 100644
index 0000000..7bd7428
--- /dev/null
+++ b/core/java/android/util/ReflectiveProperty.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.util;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Internal class to automatically generate a Property for a given class/name pair, given the
+ * specification of {@link Property#of(java.lang.Class, java.lang.Class, java.lang.String)}
+ */
+class ReflectiveProperty<T, V> extends Property<T, V> {
+
+ private static final String PREFIX_GET = "get";
+ private static final String PREFIX_IS = "is";
+ private static final String PREFIX_SET = "set";
+ private Method mSetter;
+ private Method mGetter;
+ private Field mField;
+
+ /**
+ * For given property name 'name', look for getName/isName method or 'name' field.
+ * Also look for setName method (optional - could be readonly). Failing method getters and
+ * field results in throwing NoSuchPropertyException.
+ *
+ * @param propertyHolder The class on which the methods or field are found
+ * @param name The name of the property, where this name is capitalized and appended to
+ * "get" and "is to search for the appropriate methods. If the get/is methods are not found,
+ * the constructor will search for a field with that exact name.
+ */
+ public ReflectiveProperty(Class<T> propertyHolder, Class<V> valueType, String name) {
+ // TODO: cache reflection info for each new class/name pair
+ super(valueType, name);
+ char firstLetter = Character.toUpperCase(name.charAt(0));
+ String theRest = name.substring(1);
+ String capitalizedName = firstLetter + theRest;
+ String getterName = PREFIX_GET + capitalizedName;
+ try {
+ mGetter = propertyHolder.getMethod(getterName, (Class<?>[])null);
+ } catch (NoSuchMethodException e) {
+ // getName() not available - try isName() instead
+ getterName = PREFIX_IS + capitalizedName;
+ try {
+ mGetter = propertyHolder.getMethod(getterName, (Class<?>[])null);
+ } catch (NoSuchMethodException e1) {
+ // Try public field instead
+ try {
+ mField = propertyHolder.getField(name);
+ Class fieldType = mField.getType();
+ if (!typesMatch(valueType, fieldType)) {
+ throw new NoSuchPropertyException("Underlying type (" + fieldType + ") " +
+ "does not match Property type (" + valueType + ")");
+ }
+ return;
+ } catch (NoSuchFieldException e2) {
+ // no way to access property - throw appropriate exception
+ throw new NoSuchPropertyException("No accessor method or field found for"
+ + " property with name " + name);
+ }
+ }
+ }
+ Class getterType = mGetter.getReturnType();
+ // Check to make sure our getter type matches our valueType
+ if (!typesMatch(valueType, getterType)) {
+ throw new NoSuchPropertyException("Underlying type (" + getterType + ") " +
+ "does not match Property type (" + valueType + ")");
+ }
+ String setterName = PREFIX_SET + capitalizedName;
+ try {
+ mSetter = propertyHolder.getMethod(setterName, getterType);
+ } catch (NoSuchMethodException ignored) {
+ // Okay to not have a setter - just a readonly property
+ }
+ }
+
+ /**
+ * Utility method to check whether the type of the underlying field/method on the target
+ * object matches the type of the Property. The extra checks for primitive types are because
+ * generics will force the Property type to be a class, whereas the type of the underlying
+ * method/field will probably be a primitive type instead. Accept float as matching Float,
+ * etc.
+ */
+ private boolean typesMatch(Class<V> valueType, Class getterType) {
+ if (getterType != valueType) {
+ if (getterType.isPrimitive()) {
+ return (getterType == float.class && valueType == Float.class) ||
+ (getterType == int.class && valueType == Integer.class) ||
+ (getterType == boolean.class && valueType == Boolean.class) ||
+ (getterType == long.class && valueType == Long.class) ||
+ (getterType == double.class && valueType == Double.class) ||
+ (getterType == short.class && valueType == Short.class) ||
+ (getterType == byte.class && valueType == Byte.class) ||
+ (getterType == char.class && valueType == Character.class);
+ }
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void set(T object, V value) {
+ if (mSetter != null) {
+ try {
+ mSetter.invoke(object, value);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError();
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e.getCause());
+ }
+ } else if (mField != null) {
+ try {
+ mField.set(object, value);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError();
+ }
+ } else {
+ throw new NoSuchPropertyException("Property is read-only; set() is not implemented");
+ }
+ }
+
+ @Override
+ public V get(T object) {
+ if (mGetter != null) {
+ try {
+ return (V) mGetter.invoke(object, (Object[])null);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError();
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e.getCause());
+ }
+ } else if (mField != null) {
+ try {
+ return (V) mField.get(object);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError();
+ }
+ }
+ // Should not get here: there should always be a non-null getter or field
+ throw new AssertionError();
+ }
+
+ /**
+ * Returns false if there is no setter or public field underlying this Property.
+ */
+ @Override
+ public boolean isReadOnly() {
+ return (mSetter == null && mField == null);
+ }
+}
diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java
index 2603281..ec94fe7 100644
--- a/core/java/android/view/GLES20RecordingCanvas.java
+++ b/core/java/android/view/GLES20RecordingCanvas.java
@@ -25,7 +25,7 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
-import java.util.HashSet;
+import java.util.ArrayList;
/**
* An implementation of a GL canvas that records drawing operations.
@@ -37,7 +37,7 @@ class GLES20RecordingCanvas extends GLES20Canvas {
// These lists ensure that any Bitmaps recorded by a DisplayList are kept alive as long
// as the DisplayList is alive.
@SuppressWarnings({"MismatchedQueryAndUpdateOfCollection"})
- private final HashSet<Bitmap> mBitmaps = new HashSet<Bitmap>();
+ private final ArrayList<Bitmap> mBitmaps = new ArrayList<Bitmap>(5);
GLES20RecordingCanvas(boolean translucent) {
super(true, translucent);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 70218ac..74926bb 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16,6 +16,8 @@
package android.view;
+import android.util.FloatProperty;
+import android.util.Property;
import com.android.internal.R;
import com.android.internal.util.Predicate;
import com.android.internal.view.menu.MenuBuilder;
@@ -12436,6 +12438,169 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit
return getVerticalScrollFactor();
}
+ //
+ // Properties
+ //
+ /**
+ * A Property wrapper around the <code>alpha</code> functionality handled by the
+ * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods.
+ */
+ static Property<View, Float> ALPHA = new FloatProperty<View>("alpha") {
+ @Override
+ public void setValue(View object, float value) {
+ object.setAlpha(value);
+ }
+
+ @Override
+ public Float get(View object) {
+ return object.getAlpha();
+ }
+ };
+
+ /**
+ * A Property wrapper around the <code>translationX</code> functionality handled by the
+ * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods.
+ */
+ public static Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") {
+ @Override
+ public void setValue(View object, float value) {
+ object.setTranslationX(value);
+ }
+
+ @Override
+ public Float get(View object) {
+ return object.getTranslationX();
+ }
+ };
+
+ /**
+ * A Property wrapper around the <code>translationY</code> functionality handled by the
+ * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods.
+ */
+ public static Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") {
+ @Override
+ public void setValue(View object, float value) {
+ object.setTranslationY(value);
+ }
+
+ @Override
+ public Float get(View object) {
+ return object.getTranslationY();
+ }
+ };
+
+ /**
+ * A Property wrapper around the <code>x</code> functionality handled by the
+ * {@link View#setX(float)} and {@link View#getX()} methods.
+ */
+ public static Property<View, Float> X = new FloatProperty<View>("x") {
+ @Override
+ public void setValue(View object, float value) {
+ object.setX(value);
+ }
+
+ @Override
+ public Float get(View object) {
+ return object.getX();
+ }
+ };
+
+ /**
+ * A Property wrapper around the <code>y</code> functionality handled by the
+ * {@link View#setY(float)} and {@link View#getY()} methods.
+ */
+ public static Property<View, Float> Y = new FloatProperty<View>("y") {
+ @Override
+ public void setValue(View object, float value) {
+ object.setY(value);
+ }
+
+ @Override
+ public Float get(View object) {
+ return object.getY();
+ }
+ };
+
+ /**
+ * A Property wrapper around the <code>rotation</code> functionality handled by the
+ * {@link View#setRotation(float)} and {@link View#getRotation()} methods.
+ */
+ public static Property<View, Float> ROTATION = new FloatProperty<View>("rotation") {
+ @Override
+ public void setValue(View object, float value) {
+ object.setRotation(value);
+ }
+
+ @Override
+ public Float get(View object) {
+ return object.getRotation();
+ }
+ };
+
+ /**
+ * A Property wrapper around the <code>rotationX</code> functionality handled by the
+ * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods.
+ */
+ public static Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") {
+ @Override
+ public void setValue(View object, float value) {
+ object.setRotationX(value);
+ }
+
+ @Override
+ public Float get(View object) {
+ return object.getRotationX();
+ }
+ };
+
+ /**
+ * A Property wrapper around the <code>rotationY</code> functionality handled by the
+ * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods.
+ */
+ public static Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") {
+ @Override
+ public void setValue(View object, float value) {
+ object.setRotationY(value);
+ }
+
+ @Override
+ public Float get(View object) {
+ return object.getRotationY();
+ }
+ };
+
+ /**
+ * A Property wrapper around the <code>scaleX</code> functionality handled by the
+ * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods.
+ */
+ public static Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") {
+ @Override
+ public void setValue(View object, float value) {
+ object.setScaleX(value);
+ }
+
+ @Override
+ public Float get(View object) {
+ return object.getScaleX();
+ }
+ };
+
+ /**
+ * A Property wrapper around the <code>scaleY</code> functionality handled by the
+ * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods.
+ */
+ public static Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") {
+ @Override
+ public void setValue(View object, float value) {
+ object.setScaleY(value);
+ }
+
+ @Override
+ public Float get(View object) {
+ return object.getScaleY();
+ }
+ };
+
/**
* A MeasureSpec encapsulates the layout requirements passed from parent to child.
* Each MeasureSpec represents a requirement for either the width or the height.