summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Mathias Agopian <mathias@google.com> 2010-08-20 06:27:27 -0700
committer Android Git Automerger <android-git-automerger@android.com> 2010-08-20 06:27:27 -0700
commit1d8b34ecbb97063db49ae2f55a91f44fbafbb1f2 (patch)
tree7cb9f3f09ae718ca0c0b8933c6bad0b2b43b1237
parenta2c1583eacec13696449038f3b29cf0191f6d0e3 (diff)
parentcf6f0d58a8444427a5aea372af86fca89386f987 (diff)
Merge branch 'master' of ssh://android-git:29418/platform/frameworks/base
-rw-r--r--api/current.xml226
-rwxr-xr-xcore/java/android/animation/Animator.java314
-rw-r--r--core/java/android/animation/DoubleEvaluator.java4
-rw-r--r--core/java/android/animation/FloatEvaluator.java4
-rw-r--r--core/java/android/animation/IntEvaluator.java4
-rw-r--r--core/java/android/animation/PropertyAnimator.java407
-rw-r--r--core/java/android/animation/PropertyValuesHolder.java514
7 files changed, 742 insertions, 731 deletions
diff --git a/api/current.xml b/api/current.xml
index 9c35a53613fb..3de7fca4c3d1 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -19952,67 +19952,24 @@
>
<parameter name="duration" type="long">
</parameter>
-<parameter name="keyframes" type="android.animation.Keyframe...">
+<parameter name="values" type="T...">
</parameter>
</constructor>
-<constructor name="Animator"
- type="android.animation.Animator"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="duration" type="long">
-</parameter>
-<parameter name="valueFrom" type="float">
-</parameter>
-<parameter name="valueTo" type="float">
-</parameter>
-</constructor>
-<constructor name="Animator"
- type="android.animation.Animator"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="duration" type="long">
-</parameter>
-<parameter name="valueFrom" type="int">
-</parameter>
-<parameter name="valueTo" type="int">
-</parameter>
-</constructor>
-<constructor name="Animator"
- type="android.animation.Animator"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="duration" type="long">
-</parameter>
-<parameter name="valueFrom" type="double">
-</parameter>
-<parameter name="valueTo" type="double">
-</parameter>
-</constructor>
-<constructor name="Animator"
- type="android.animation.Animator"
+<method name="addUpdateListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
-<parameter name="duration" type="long">
-</parameter>
-<parameter name="valueFrom" type="java.lang.Object">
-</parameter>
-<parameter name="valueTo" type="java.lang.Object">
+<parameter name="listener" type="android.animation.Animator.AnimatorUpdateListener">
</parameter>
-</constructor>
-<method name="addUpdateListener"
- return="void"
+</method>
+<method name="getAnimatedValue"
+ return="java.lang.Object"
abstract="false"
native="false"
synchronized="false"
@@ -20021,8 +19978,6 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="listener" type="android.animation.Animator.AnimatorUpdateListener">
-</parameter>
</method>
<method name="getAnimatedValue"
return="java.lang.Object"
@@ -20034,6 +19989,8 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="propertyName" type="java.lang.String">
+</parameter>
</method>
<method name="getCurrentPlayTime"
return="long"
@@ -20090,28 +20047,6 @@
visibility="public"
>
</method>
-<method name="getValueFrom"
- return="java.lang.Object"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getValueTo"
- return="java.lang.Object"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
<method name="isRunning"
return="boolean"
abstract="false"
@@ -20238,7 +20173,7 @@
<parameter name="startDelay" type="long">
</parameter>
</method>
-<method name="setValueFrom"
+<method name="setValues"
return="void"
abstract="false"
native="false"
@@ -20248,10 +20183,10 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="valueFrom" type="java.lang.Object">
+<parameter name="values" type="android.animation.PropertyValuesHolder...">
</parameter>
</method>
-<method name="setValueTo"
+<method name="setValues"
return="void"
abstract="false"
native="false"
@@ -20261,7 +20196,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="valueTo" type="java.lang.Object">
+<parameter name="values" type="T...">
</parameter>
</method>
<field name="INFINITE"
@@ -20594,15 +20529,13 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="duration" type="int">
+<parameter name="duration" type="long">
</parameter>
<parameter name="target" type="java.lang.Object">
</parameter>
<parameter name="propertyName" type="java.lang.String">
</parameter>
-<parameter name="valueFrom" type="float">
-</parameter>
-<parameter name="valueTo" type="float">
+<parameter name="values" type="T...">
</parameter>
</constructor>
<constructor name="PropertyAnimator"
@@ -20612,131 +20545,90 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="duration" type="int">
+<parameter name="duration" type="long">
</parameter>
<parameter name="target" type="java.lang.Object">
</parameter>
-<parameter name="propertyName" type="java.lang.String">
-</parameter>
-<parameter name="valueTo" type="float">
+<parameter name="values" type="android.animation.PropertyValuesHolder...">
</parameter>
</constructor>
-<constructor name="PropertyAnimator"
- type="android.animation.PropertyAnimator"
+<method name="getPropertyName"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
-<parameter name="duration" type="int">
-</parameter>
-<parameter name="target" type="java.lang.Object">
-</parameter>
-<parameter name="propertyName" type="java.lang.String">
-</parameter>
-<parameter name="valueFrom" type="int">
-</parameter>
-<parameter name="valueTo" type="int">
-</parameter>
-</constructor>
-<constructor name="PropertyAnimator"
- type="android.animation.PropertyAnimator"
+</method>
+<method name="getTarget"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
-<parameter name="duration" type="int">
-</parameter>
-<parameter name="target" type="java.lang.Object">
-</parameter>
-<parameter name="propertyName" type="java.lang.String">
-</parameter>
-<parameter name="valueTo" type="int">
-</parameter>
-</constructor>
-<constructor name="PropertyAnimator"
- type="android.animation.PropertyAnimator"
+</method>
+<method name="setPropertyName"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
-<parameter name="duration" type="int">
-</parameter>
-<parameter name="target" type="java.lang.Object">
-</parameter>
<parameter name="propertyName" type="java.lang.String">
</parameter>
-<parameter name="valueFrom" type="double">
-</parameter>
-<parameter name="valueTo" type="double">
-</parameter>
-</constructor>
-<constructor name="PropertyAnimator"
- type="android.animation.PropertyAnimator"
+</method>
+<method name="setTarget"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
-<parameter name="duration" type="int">
-</parameter>
<parameter name="target" type="java.lang.Object">
</parameter>
-<parameter name="propertyName" type="java.lang.String">
-</parameter>
-<parameter name="valueTo" type="double">
-</parameter>
-</constructor>
-<constructor name="PropertyAnimator"
- type="android.animation.PropertyAnimator"
+</method>
+</class>
+<class name="PropertyValuesHolder"
+ extends="java.lang.Object"
+ abstract="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
-<parameter name="duration" type="int">
-</parameter>
-<parameter name="target" type="java.lang.Object">
-</parameter>
-<parameter name="propertyName" type="java.lang.String">
-</parameter>
-<parameter name="valueFrom" type="java.lang.Object">
-</parameter>
-<parameter name="valueTo" type="java.lang.Object">
-</parameter>
-</constructor>
-<constructor name="PropertyAnimator"
- type="android.animation.PropertyAnimator"
+<constructor name="PropertyValuesHolder"
+ type="android.animation.PropertyValuesHolder"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
-<parameter name="duration" type="int">
-</parameter>
-<parameter name="target" type="java.lang.Object">
-</parameter>
-<parameter name="propertyName" type="java.lang.String">
-</parameter>
-<parameter name="valueTo" type="java.lang.Object">
+<parameter name="values" type="T...">
</parameter>
</constructor>
-<constructor name="PropertyAnimator"
- type="android.animation.PropertyAnimator"
+<constructor name="PropertyValuesHolder"
+ type="android.animation.PropertyValuesHolder"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
-<parameter name="duration" type="int">
-</parameter>
-<parameter name="target" type="java.lang.Object">
-</parameter>
<parameter name="propertyName" type="java.lang.String">
</parameter>
-<parameter name="keyframes" type="android.animation.Keyframe...">
+<parameter name="values" type="T...">
</parameter>
</constructor>
<method name="getGetter"
@@ -20772,8 +20664,8 @@
visibility="public"
>
</method>
-<method name="getTarget"
- return="java.lang.Object"
+<method name="setEvaluator"
+ return="void"
abstract="false"
native="false"
synchronized="false"
@@ -20782,6 +20674,8 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="evaluator" type="android.animation.TypeEvaluator">
+</parameter>
</method>
<method name="setGetter"
return="void"
@@ -20822,7 +20716,7 @@
<parameter name="setter" type="java.lang.reflect.Method">
</parameter>
</method>
-<method name="setTarget"
+<method name="setValues"
return="void"
abstract="false"
native="false"
@@ -20832,7 +20726,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="target" type="java.lang.Object">
+<parameter name="values" type="T...">
</parameter>
</method>
</class>
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index cd6531b5bda7..951d104ad3fe 100755
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -26,6 +26,7 @@ import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import java.util.ArrayList;
+import java.util.HashMap;
/**
* This class provides a simple timing engine for running animations
@@ -39,7 +40,7 @@ import java.util.ArrayList;
* out of an animation. This behavior can be changed by calling
* {@link Animator#setInterpolator(Interpolator)}.</p>
*/
-public class Animator extends Animatable {
+public class Animator<T> extends Animatable {
/**
* Internal constants
@@ -164,12 +165,6 @@ public class Animator extends Animatable {
// How long the animation should last in ms
private long mDuration;
- // The value that the animation should start from, set in the constructor
- private Object mValueFrom;
-
- // The value that the animation should animate to, set in the constructor
- private Object mValueTo;
-
// The amount of time in ms to delay starting the animation after start() is called
private long mStartDelay = 0;
@@ -195,29 +190,22 @@ public class Animator extends Animatable {
private Interpolator mInterpolator = sDefaultInterpolator;
/**
- * The type evaluator used to calculate the animated values. This evaluator is determined
- * automatically based on the type of the start/end objects passed into the constructor,
- * but the system only knows about the primitive types int, double, and float. Any other
- * type will need to set the evaluator to a custom evaluator for that type.
- */
- private TypeEvaluator mEvaluator;
-
- /**
* The set of listeners to be sent events through the life of an animation.
*/
private ArrayList<AnimatorUpdateListener> mUpdateListeners = null;
/**
- * The current value calculated by the animation. The value is calculated in animateFraction(),
- * prior to calling the setter (if set) and sending out the onAnimationUpdate() callback
- * to the update listeners.
+ * The property/value sets being animated.
*/
- private Object mAnimatedValue = null;
+ HashMap<String, PropertyValuesHolder> mValues;
/**
- * The set of keyframes (time/value pairs) that define this animation.
+ * This value is used in the simple/common case of animating just one value; the user
+ * may call getAnimatedValue(), which should return the value of the first (and only)
+ * ProeprtyValuesHolder animated value, which is looked up using this string.
*/
- private KeyframeSet mKeyframeSet = null;
+ String mFirstPropertyName;
+
/**
* The type of the values, as determined by the valueFrom/valueTo properties.
@@ -267,144 +255,120 @@ public class Animator extends Animatable {
int valueType = a.getInt(com.android.internal.R.styleable.Animator_valueType,
VALUE_TYPE_FLOAT);
+ Object valueFrom = null;
+ Object valueTo = null;
+
switch (valueType) {
case VALUE_TYPE_FLOAT:
- mValueFrom = a.getFloat(com.android.internal.R.styleable.Animator_valueFrom, 0f);
- mValueTo = a.getFloat(com.android.internal.R.styleable.Animator_valueTo, 0f);
+ valueFrom = a.getFloat(com.android.internal.R.styleable.Animator_valueFrom, 0f);
+ valueTo = a.getFloat(com.android.internal.R.styleable.Animator_valueTo, 0f);
mValueType = float.class;
break;
case VALUE_TYPE_INT:
- mValueFrom = a.getInt(com.android.internal.R.styleable.Animator_valueFrom, 0);
- mValueTo = a.getInt(com.android.internal.R.styleable.Animator_valueTo, 0);
+ valueFrom = a.getInt(com.android.internal.R.styleable.Animator_valueFrom, 0);
+ valueTo = a.getInt(com.android.internal.R.styleable.Animator_valueTo, 0);
mValueType = int.class;
break;
case VALUE_TYPE_DOUBLE:
- mValueFrom = (double)
+ valueFrom = (double)
a.getFloat(com.android.internal.R.styleable.Animator_valueFrom, 0f);
- mValueTo = (double)
+ valueTo = (double)
a.getFloat(com.android.internal.R.styleable.Animator_valueTo, 0f);
mValueType = double.class;
break;
case VALUE_TYPE_COLOR:
- mValueFrom = a.getInt(com.android.internal.R.styleable.Animator_valueFrom, 0);
- mValueTo = a.getInt(com.android.internal.R.styleable.Animator_valueTo, 0);
- mEvaluator = new RGBEvaluator();
+ valueFrom = a.getInt(com.android.internal.R.styleable.Animator_valueFrom, 0);
+ valueTo = a.getInt(com.android.internal.R.styleable.Animator_valueTo, 0);
+ setEvaluator(new RGBEvaluator());
mValueType = int.class;
break;
case VALUE_TYPE_CUSTOM:
// TODO: How to get an 'Object' value?
- mValueFrom = a.getFloat(com.android.internal.R.styleable.Animator_valueFrom, 0f);
- mValueTo = a.getFloat(com.android.internal.R.styleable.Animator_valueTo, 0f);
+ valueFrom = a.getFloat(com.android.internal.R.styleable.Animator_valueFrom, 0f);
+ valueTo = a.getFloat(com.android.internal.R.styleable.Animator_valueTo, 0f);
mValueType = Object.class;
break;
}
+ mValues = new HashMap<String, PropertyValuesHolder>(1);
+ mFirstPropertyName = "";
+ PropertyValuesHolder valuesHolder = new PropertyValuesHolder(mFirstPropertyName,
+ valueFrom, valueTo);
+ mValues.put(mFirstPropertyName, valuesHolder);
+
mRepeatCount = a.getInt(com.android.internal.R.styleable.Animator_repeatCount, mRepeatCount);
mRepeatMode = a.getInt(com.android.internal.R.styleable.Animator_repeatMode, RESTART);
a.recycle();
}
- private Animator(long duration, Object valueFrom, Object valueTo, Class valueType) {
- mDuration = duration;
- mValueFrom = valueFrom;
- mValueTo= valueTo;
- this.mValueType = valueType;
- }
/**
- * This constructor takes a set of {@link Keyframe} objects that define the values
- * for the animation, along with the times at which those values will hold true during
- * the animation.
+ * Constructs an Animator object with the specified duration and set of
+ * values. If the values are a set of PropertyValuesHolder objects, then these objects
+ * define the potentially multiple properties being animated and the values the properties are
+ * animated between. Otherwise, the values define a single set of values animated between.
*
* @param duration The length of the animation, in milliseconds.
- * @param keyframes The set of keyframes that define the time/value pairs for the animation.
+ * @param values The set of values to animate between. If these values are not
+ * PropertyValuesHolder objects, then there should be more than one value, since the values
+ * determine the interval to animate between.
*/
- public Animator(long duration, Keyframe...keyframes) {
+ public Animator(long duration, T...values) {
mDuration = duration;
- mKeyframeSet = new KeyframeSet(keyframes);
- mValueType = keyframes[0].getType();
- }
-
- /**
- * A constructor that takes <code>float</code> values.
- *
- * @param duration The length of the animation, in milliseconds.
- * @param valueFrom The initial value of the property when the animation begins.
- * @param valueTo The value to which the property will animate.
- */
- public Animator(long duration, float valueFrom, float valueTo) {
- this(duration, valueFrom, valueTo, float.class);
- }
-
- /**
- * A constructor that takes <code>int</code> values.
- *
- * @param duration The length of the animation, in milliseconds.
- * @param valueFrom The initial value of the property when the animation begins.
- * @param valueTo The value to which the property will animate.
- */
- public Animator(long duration, int valueFrom, int valueTo) {
- this(duration, valueFrom, valueTo, int.class);
- }
-
- /**
- * A constructor that takes <code>double</code> values.
- *
- * @param duration The length of the animation, in milliseconds.
- * @param valueFrom The initial value of the property when the animation begins.
- * @param valueTo The value to which the property will animate.
- */
- public Animator(long duration, double valueFrom, double valueTo) {
- this(duration, valueFrom, valueTo, double.class);
- }
-
- /**
- * A constructor that takes <code>Object</code> values.
- *
- * @param duration The length of the animation, in milliseconds.
- * @param valueFrom The initial value of the property when the animation begins.
- * @param valueTo The value to which the property will animate.
- */
- public Animator(long duration, Object valueFrom, Object valueTo) {
- this(duration, valueFrom, valueTo,
- (valueFrom != null) ? valueFrom.getClass() : valueTo.getClass());
- }
-
- /**
- * Internal constructor that takes a single <code>float</code> value.
- * This constructor is called by PropertyAnimator.
- *
- * @param duration The length of the animation, in milliseconds.
- * @param valueFrom The initial value of the property when the animation begins.
- * @param valueTo The value to which the property will animate.
- */
- Animator(long duration, float valueTo) {
- this(duration, null, valueTo, float.class);
+ if (values.length > 0) {
+ setValues(values);
+ }
}
- /**
- * Internal constructor that takes a single <code>int</code> value.
- * This constructor is called by PropertyAnimator.
- *
- * @param duration The length of the animation, in milliseconds.
- * @param valueFrom The initial value of the property when the animation begins.
- * @param valueTo The value to which the property will animate.
- */
- Animator(long duration, int valueTo) {
- this(duration, null, valueTo, int.class);
+ public void setValues(PropertyValuesHolder... values) {
+ int numValues = values.length;
+ mValues = new HashMap<String, PropertyValuesHolder>(numValues);
+ for (int i = 0; i < numValues; ++i) {
+ PropertyValuesHolder valuesHolder = (PropertyValuesHolder) values[i];
+ mValues.put(valuesHolder.getPropertyName(), valuesHolder);
+ }
+ if (numValues > 0 && values[0] != null) {
+ mFirstPropertyName = ((PropertyValuesHolder) values[0]).getPropertyName();
+ } else {
+ mFirstPropertyName = "";
+ }
}
/**
- * Internal constructor that takes a single <code>double</code> value.
- * This constructor is called by PropertyAnimator.
+ * Sets the values to animate between for this animation. If <code>values</code> is
+ * a set of PropertyValuesHolder objects, these objects will become the set of properties
+ * animated and the values that those properties are animated between. Otherwise, this method
+ * will set only one set of values for the Animator. Also, if the values are not
+ * PropertyValuesHolder objects and if there are already multiple sets of
+ * values defined for this Animator via
+ * more than one PropertyValuesHolder objects, this method will set the values for
+ * the first of those objects.
*
- * @param duration The length of the animation, in milliseconds.
- * @param valueFrom The initial value of the property when the animation begins.
- * @param valueTo The value to which the property will animate.
+ * @param values The set of values to animate between.
*/
- Animator(long duration, double valueTo) {
- this(duration, null, valueTo, double.class);
+ public void setValues(T... values) {
+ if (values[0] instanceof PropertyValuesHolder) {
+ int numValues = values.length;
+ mValues = new HashMap<String, PropertyValuesHolder>(numValues);
+ for (int i = 0; i < numValues; ++i) {
+ PropertyValuesHolder valuesHolder = (PropertyValuesHolder) values[i];
+ mValues.put(valuesHolder.getPropertyName(), valuesHolder);
+ }
+ if (numValues > 0 && values[0] != null) {
+ mFirstPropertyName = ((PropertyValuesHolder) values[0]).getPropertyName();
+ } else {
+ mFirstPropertyName = "";
+ }
+ } else {
+ if (mValues == null) {
+ setValues(new PropertyValuesHolder[]{
+ new PropertyValuesHolder("", (Object[])values)});
+ } else {
+ PropertyValuesHolder valuesHolder = mValues.get(mFirstPropertyName);
+ valuesHolder.setValues(values);
+ }
+ }
}
/**
@@ -418,9 +382,8 @@ public class Animator extends Animatable {
* that internal mechanisms for the animation are set up correctly.</p>
*/
void initAnimation() {
- if (mEvaluator == null) {
- mEvaluator = (mValueType == int.class) ? sIntEvaluator :
- (mValueType == double.class) ? sDoubleEvaluator : sFloatEvaluator;
+ for (PropertyValuesHolder pvHolder: mValues.values()) {
+ pvHolder.init();
}
mCurrentIteration = 0;
mInitialized = true;
@@ -599,67 +562,6 @@ public class Animator extends Animatable {
}
/**
- * Gets the set of keyframes that define this animation.
- *
- * @return KeyframeSet The set of keyframes for this animation.
- */
- KeyframeSet getKeyframes() {
- return mKeyframeSet;
- }
-
- /**
- * Gets the value that this animation will start from.
- *
- * @return Object The starting value for the animation.
- */
- public Object getValueFrom() {
- if (mKeyframeSet != null) {
- return mKeyframeSet.mKeyframes.get(0).getValue();
- }
- return mValueFrom;
- }
-
- /**
- * Sets the value that this animation will start from.
- */
- public void setValueFrom(Object valueFrom) {
- if (mKeyframeSet != null) {
- Keyframe kf = mKeyframeSet.mKeyframes.get(0);
- kf.setValue(valueFrom);
- } else {
- mValueFrom = valueFrom;
- }
- }
-
- /**
- * Gets the value that this animation will animate to.
- *
- * @return Object The ending value for the animation.
- */
- public Object getValueTo() {
- if (mKeyframeSet != null) {
- int numKeyframes = mKeyframeSet.mKeyframes.size();
- return mKeyframeSet.mKeyframes.get(numKeyframes - 1).getValue();
- }
- return mValueTo;
- }
-
- /**
- * Sets the value that this animation will animate to.
- *
- * @return Object The ending value for the animation.
- */
- public void setValueTo(Object valueTo) {
- if (mKeyframeSet != null) {
- int numKeyframes = mKeyframeSet.mKeyframes.size();
- Keyframe kf = mKeyframeSet.mKeyframes.get(numKeyframes - 1);
- kf.setValue(valueTo);
- } else {
- mValueTo = valueTo;
- }
- }
-
- /**
* The amount of time, in milliseconds, between each frame of the animation. This is a
* requested time that the animation will attempt to honor, but the actual delay between
* frames may be different, depending on system load and capabilities. This is a static
@@ -673,17 +575,33 @@ public class Animator extends Animatable {
}
/**
- * The most recent value calculated by this <code>Animator</code> for the property
- * being animated. This value is only sensible while the animation is running. The main
+ * The most recent value calculated by this <code>Animator</code> when there is just one
+ * property being animated. This value is only sensible while the animation is running. The main
* purpose for this read-only property is to retrieve the value from the <code>Animator</code>
* during a call to {@link AnimatorUpdateListener#onAnimationUpdate(Animator)}, which
* is called during each animation frame, immediately after the value is calculated.
*
* @return animatedValue The value most recently calculated by this <code>Animator</code> for
- * the property specified in the constructor.
+ * the single property being animated. If there are several properties being animated
+ * (specified by several PropertyValuesHolder objects in the constructor), this function
+ * returns the animated value for the first of those objects.
*/
public Object getAnimatedValue() {
- return mAnimatedValue;
+ return getAnimatedValue(mFirstPropertyName);
+ }
+
+ /**
+ * The most recent value calculated by this <code>Animator</code> for <code>propertyName</code>.
+ * The main purpose for this read-only property is to retrieve the value from the
+ * <code>Animator</code> during a call to
+ * {@link AnimatorUpdateListener#onAnimationUpdate(Animator)}, which
+ * is called during each animation frame, immediately after the value is calculated.
+ *
+ * @return animatedValue The value most recently calculated for the named property
+ * by this <code>Animator</code>.
+ */
+ public Object getAnimatedValue(String propertyName) {
+ return mValues.get(mFirstPropertyName).getAnimatedValue();
}
/**
@@ -781,14 +699,26 @@ public class Animator extends Animatable {
* For example, when running an animation on color values, the {@link RGBEvaluator}
* should be used to get correct RGB color interpolation.
*
+ * <p>If this Animator has only one set of values being animated between, this evaluator
+ * will be used for that set. If there are several sets of values being animated, which is
+ * the case if PropertyValuesHOlder objects were set on the Animator, then the evaluator
+ * is assigned just to the first PropertyValuesHolder object.</p>
+ *
* @param value the evaluator to be used this animation
*/
public void setEvaluator(TypeEvaluator value) {
- if (value != null) {
- mEvaluator = value;
+ if (value != null && mValues != null) {
+ mValues.get(mFirstPropertyName).setEvaluator(value);
}
}
+ /**
+ * Start the animation playing. This version of start() takes a boolean flag that indicates
+ * whether the animation should play in reverse. The flag is usually false, but may be set
+ * to true if called from the reverse() method/
+ *
+ * @param playBackwards Whether the Animator should start playing in reverse.
+ */
private void start(boolean playBackwards) {
mPlayingBackwards = playBackwards;
mPlayingState = STOPPED;
@@ -998,10 +928,8 @@ public class Animator extends Animatable {
*/
void animateValue(float fraction) {
fraction = mInterpolator.getInterpolation(fraction);
- if (mKeyframeSet != null) {
- mAnimatedValue = mKeyframeSet.getValue(fraction, mEvaluator);
- } else {
- mAnimatedValue = mEvaluator.evaluate(fraction, mValueFrom, mValueTo);
+ for (PropertyValuesHolder valuesHolder : mValues.values()) {
+ valuesHolder.calculateValue(fraction);
}
if (mUpdateListeners != null) {
int numListeners = mUpdateListeners.size();
diff --git a/core/java/android/animation/DoubleEvaluator.java b/core/java/android/animation/DoubleEvaluator.java
index 86e3f225e64c..e46eb372e554 100644
--- a/core/java/android/animation/DoubleEvaluator.java
+++ b/core/java/android/animation/DoubleEvaluator.java
@@ -36,7 +36,7 @@ public class DoubleEvaluator implements TypeEvaluator {
* <code>fraction</code> parameter.
*/
public Object evaluate(float fraction, Object startValue, Object endValue) {
- double startDouble = (Double) startValue;
- return startDouble + fraction * ((Double) endValue - startDouble);
+ double startDouble = ((Number) startValue).doubleValue();
+ return startDouble + fraction * (((Number) endValue).doubleValue() - startDouble);
}
} \ No newline at end of file
diff --git a/core/java/android/animation/FloatEvaluator.java b/core/java/android/animation/FloatEvaluator.java
index 29a6f71c2246..9e2054d0dc02 100644
--- a/core/java/android/animation/FloatEvaluator.java
+++ b/core/java/android/animation/FloatEvaluator.java
@@ -36,7 +36,7 @@ public class FloatEvaluator implements TypeEvaluator {
* <code>fraction</code> parameter.
*/
public Object evaluate(float fraction, Object startValue, Object endValue) {
- float startFloat = (Float) startValue;
- return startFloat + fraction * ((Float) endValue - startFloat);
+ float startFloat = ((Number) startValue).floatValue();
+ return startFloat + fraction * (((Number) 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 7a2911a5a2b3..7288927f783b 100644
--- a/core/java/android/animation/IntEvaluator.java
+++ b/core/java/android/animation/IntEvaluator.java
@@ -36,7 +36,7 @@ public class IntEvaluator implements TypeEvaluator {
* <code>fraction</code> parameter.
*/
public Object evaluate(float fraction, Object startValue, Object endValue) {
- int startInt = (Integer) startValue;
- return (int) (startInt + fraction * ((Integer) endValue - startInt));
+ int startInt = ((Number) startValue).intValue();
+ return (int) (startInt + fraction * (((Number) endValue).intValue() - startInt));
}
} \ No newline at end of file
diff --git a/core/java/android/animation/PropertyAnimator.java b/core/java/android/animation/PropertyAnimator.java
index eac9798548c4..9366a713971e 100644
--- a/core/java/android/animation/PropertyAnimator.java
+++ b/core/java/android/animation/PropertyAnimator.java
@@ -33,35 +33,13 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
* are then determined internally and the animation will call these functions as necessary to
* animate the property.
*/
-public final class PropertyAnimator extends Animator {
+public final class PropertyAnimator<T> extends Animator<T> {
// The target object on which the property exists, set in the constructor
private Object mTarget;
private String mPropertyName;
- private Method mGetter = null;
-
- // The property setter that is assigned internally, based on the propertyName passed into
- // the constructor
- private Method mSetter;
-
- // These maps hold all property entries for a particular class. This map
- // is used to speed up property/setter/getter lookups for a given class/property
- // combination. No need to use reflection on the combination more than once.
- private static final HashMap<Object, HashMap<String, Method>> sSetterPropertyMap =
- new HashMap<Object, HashMap<String, Method>>();
- private static final HashMap<Object, HashMap<String, Method>> sGetterPropertyMap =
- new HashMap<Object, HashMap<String, Method>>();
-
- // This lock is used to ensure that only one thread is accessing the property maps
- // at a time.
- private ReentrantReadWriteLock propertyMapLock = new ReentrantReadWriteLock();
-
- // Used to pass single value to varargs parameter in setter invocation
- private Object[] mTmpValueArray = new Object[1];
-
-
/**
* 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.
@@ -75,9 +53,19 @@ public final class PropertyAnimator extends Animator {
* <code>valueFrom</code> and <code>valueTo</code> properties, otherwise the call to
* the setter function will fail.</p>
*
+ * <p>If this PropertyAnimator has been set up to animate several properties together,
+ * 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.
*/
public void setPropertyName(String propertyName) {
+ if (mValues != null) {
+ // should always be the case
+ PropertyValuesHolder valuesHolder = mValues.get(mFirstPropertyName);
+ valuesHolder.setPropertyName(propertyName);
+ mFirstPropertyName = propertyName;
+ }
mPropertyName = propertyName;
}
@@ -94,67 +82,6 @@ public final class PropertyAnimator extends Animator {
}
/**
- * Sets the <code>Method</code> that is called with the animated values calculated
- * during the animation. Setting the setter method is an alternative to supplying a
- * {@link #setPropertyName(String) propertyName} from which the method is derived. This
- * approach is more direct, and is especially useful when a function must be called that does
- * not correspond to the convention of <code>setName()</code>. For example, if a function
- * called <code>offset()</code> is to be called with the animated values, there is no way
- * to tell <code>PropertyAnimator</code> how to call that function simply through a property
- * name, so a setter method should be supplied instead.
- *
- * <p>Note that the setter function must take the same parameter type as the
- * <code>valueFrom</code> and <code>valueTo</code> properties, otherwise the call to
- * the setter function will fail.</p>
- *
- * @param setter The setter method that should be called with the animated values.
- */
- public void setSetter(Method setter) {
- mSetter = setter;
- }
-
- /**
- * Gets the <code>Method</code> that is called with the animated values calculated
- * during the animation.
- */
- public Method getSetter() {
- return mSetter;
- }
-
- /**
- * Sets the <code>Method</code> that is called to get unsupplied <code>valueFrom</code> or
- * <code>valueTo</code> properties. Setting the getter method is an alternative to supplying a
- * {@link #setPropertyName(String) propertyName} from which the method is derived. This
- * approach is more direct, and is especially useful when a function must be called that does
- * not correspond to the convention of <code>setName()</code>. For example, if a function
- * called <code>offset()</code> is to be called to get an initial value, there is no way
- * to tell <code>PropertyAnimator</code> how to call that function simply through a property
- * name, so a getter method should be supplied instead.
- *
- * <p>Note that the getter method is only called whether supplied here or derived
- * from the property name, if one of <code>valueFrom</code> or <code>valueTo</code> are
- * null. If both of those values are non-null, then there is no need to get one of the
- * values and the getter is not called.
- *
- * <p>Note that the getter function must return the same parameter type as the
- * <code>valueFrom</code> and <code>valueTo</code> properties (whichever of them are
- * non-null), otherwise the call to the getter function will fail.</p>
- *
- * @param getter The getter method that should be called to get initial animation values.
- */
- public void setGetter(Method getter) {
- mGetter = getter;
- }
-
- /**
- * Gets the <code>Method</code> that is called to get unsupplied <code>valueFrom</code> or
- * <code>valueTo</code> properties.
- */
- public Method getGetter() {
- return mGetter;
- }
-
- /**
* Creates a new animation whose parameters come from the specified context and
* attributes set.
*
@@ -167,7 +94,8 @@ public final class PropertyAnimator extends Animator {
TypedArray a = context.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.PropertyAnimator);
- mPropertyName = a.getString(com.android.internal.R.styleable.PropertyAnimator_propertyName);
+ setPropertyName(a.getString(
+ com.android.internal.R.styleable.PropertyAnimator_propertyName));
a.recycle();
@@ -203,224 +131,42 @@ public final class PropertyAnimator extends Animator {
}
/**
- * A constructor that takes <code>float</code> values. When this constructor
- * is called, the system expects to find a setter for <code>propertyName</code> on
- * the target object that takes a <code>float</code> value.
- *
- * @param duration The length of the animation, in milliseconds.
- * @param target The object whose property is to be animated. This object should
- * have a public function on it called <code>setName()</code>, where <code>name</code> is
- * the name of the property passed in as the <code>propertyName</code> parameter.
- * @param propertyName The name of the property on the <code>target</code> object
- * that will be animated. Given this name, the constructor will search for a
- * setter on the target object with the name <code>setPropertyName</code>. For example,
- * if the constructor is called with <code>propertyName = "foo"</code>, then the
- * target object should have a setter function with the name <code>setFoo()</code>.
- * @param valueFrom The initial value of the property when the animation begins.
- * @param valueTo The value to which the property will animate.
- */
- public PropertyAnimator(int duration, Object target, String propertyName,
- float valueFrom, float valueTo) {
- super(duration, valueFrom, valueTo);
- mTarget = target;
- mPropertyName = propertyName;
- }
-
- /**
- * A constructor that takes a single <code>float</code> value, which is the value that the
- * target object will animate to. When this constructor
- * is called, the system expects to find a setter for <code>propertyName</code> on
- * the target object that takes a value of the same type as the <code>Object</code>s. The
- * system also expects to find a similar getter function with which to derive the starting
- * value for the animation.
- *
- * @param duration The length of the animation, in milliseconds.
- * @param target The object whose property is to be animated. This object should
- * have a public function on it called <code>setName()</code>, where <code>name</code> is
- * the name of the property passed in as the <code>propertyName</code> parameter.
- * @param propertyName The name of the property on the <code>target</code> object
- * that will be animated. Given this name, the constructor will search for a
- * setter on the target object with the name <code>setPropertyName</code>. For example,
- * if the constructor is called with <code>propertyName = "foo"</code>, then the
- * target object should have a setter function with the name <code>setFoo()</code>.
- * @param valueTo The value to which the property will animate.
- */
- public PropertyAnimator(int duration, Object target, String propertyName, float valueTo) {
- super(duration, valueTo);
- mTarget = target;
- mPropertyName = propertyName;
- }
-
- /**
- * A constructor that takes <code>int</code> values. When this constructor
- * is called, the system expects to find a setter for <code>propertyName</code> on
- * the target object that takes a <code>int</code> value.
- *
- * @param duration The length of the animation, in milliseconds.
- * @param target The object whose property is to be animated. This object should
- * have a public function on it called <code>setName()</code>, where <code>name</code> is
- * the name of the property passed in as the <code>propertyName</code> parameter.
- * @param propertyName The name of the property on the <code>target</code> object
- * that will be animated. Given this name, the constructor will search for a
- * setter on the target object with the name <code>setPropertyName</code>. For example,
- * if the constructor is called with <code>propertyName = "foo"</code>, then the
- * target object should have a setter function with the name <code>setFoo()</code>.
- * @param valueFrom The initial value of the property when the animation begins.
- * @param valueTo The value to which the property will animate.
- */
- public PropertyAnimator(int duration, Object target, String propertyName,
- int valueFrom, int valueTo) {
- super(duration, valueFrom, valueTo);
- mTarget = target;
- mPropertyName = propertyName;
- }
-
- /**
- * A constructor that takes a single <code>int</code> value, which is the value that the
- * target object will animate to. When this constructor
- * is called, the system expects to find a setter for <code>propertyName</code> on
- * the target object that takes a value of the same type as the <code>Object</code>s. The
- * system also expects to find a similar getter function with which to derive the starting
- * value for the animation.
- *
- * @param duration The length of the animation, in milliseconds.
- * @param target The object whose property is to be animated. This object should
- * have a public function on it called <code>setName()</code>, where <code>name</code> is
- * the name of the property passed in as the <code>propertyName</code> parameter.
- * @param propertyName The name of the property on the <code>target</code> object
- * that will be animated. Given this name, the constructor will search for a
- * setter on the target object with the name <code>setPropertyName</code>. For example,
- * if the constructor is called with <code>propertyName = "foo"</code>, then the
- * target object should have a setter function with the name <code>setFoo()</code>.
- * @param valueTo The value to which the property will animate.
- */
- public PropertyAnimator(int duration, Object target, String propertyName, int valueTo) {
- super(duration, valueTo);
- mTarget = target;
- mPropertyName = propertyName;
- }
-
- /**
- * A constructor that takes <code>double</code> values. When this constructor
- * is called, the system expects to find a setter for <code>propertyName</code> on
- * the target object that takes a <code>double</code> value.
- *
- * @param duration The length of the animation, in milliseconds.
- * @param target The object whose property is to be animated. This object should
- * have a public function on it called <code>setName()</code>, where <code>name</code> is
- * the name of the property passed in as the <code>propertyName</code> parameter.
- * @param propertyName The name of the property on the <code>target</code> object
- * that will be animated. Given this name, the constructor will search for a
- * setter on the target object with the name <code>setPropertyName</code>. For example,
- * if the constructor is called with <code>propertyName = "foo"</code>, then the
- * target object should have a setter function with the name <code>setFoo()</code>.
- * @param valueFrom The initial value of the property when the animation begins.
- * @param valueTo The value to which the property will animate.
- */
- public PropertyAnimator(int duration, Object target, String propertyName,
- double valueFrom, double valueTo) {
- super(duration, valueFrom, valueTo);
- mTarget = target;
- mPropertyName = propertyName;
- }
-
- /**
- * A constructor that takes a single <code>double</code> value, which is the value that the
- * target object will animate to. When this constructor
- * is called, the system expects to find a setter for <code>propertyName</code> on
- * the target object that takes a value of the same type as the <code>Object</code>s. The
- * system also expects to find a similar getter function with which to derive the starting
- * value for the animation.
+ * 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.
*
* @param duration The length of the animation, in milliseconds.
* @param target The object whose property is to be animated. This object should
- * have a public function on it called <code>setName()</code>, where <code>name</code> is
- * the name of the property passed in as the <code>propertyName</code> parameter.
- * @param propertyName The name of the property on the <code>target</code> object
- * that will be animated. Given this name, the constructor will search for a
- * setter on the target object with the name <code>setPropertyName</code>. For example,
- * if the constructor is called with <code>propertyName = "foo"</code>, then the
- * target object should have a setter function with the name <code>setFoo()</code>.
- * @param valueTo The value to which the property will animate.
+ * 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 The set of values to animate between. If there is only one value, it
+ * is assumed to be the final value being animated to, and the initial value will be
+ * derived on the fly.
*/
- public PropertyAnimator(int duration, Object target, String propertyName, double valueTo) {
- super(duration, valueTo);
+ public PropertyAnimator(long duration, Object target, String propertyName, T...values) {
+ super(duration, (T[]) values);
mTarget = target;
- mPropertyName = propertyName;
+ setPropertyName(propertyName);
}
/**
- * A constructor that takes <code>Object</code> values. When this constructor
- * is called, the system expects to find a setter for <code>propertyName</code> on
- * the target object that takes a value of the same type as the <code>Object</code>s.
+ * A constructor that takes <code>PropertyValueHolder</code> values. This constructor should
+ * be used when animating several properties at once with the same PropertyAnimator, since
+ * PropertyValuesHolder allows you to associate a set of animation values with a property
+ * name.
*
* @param duration The length of the animation, in milliseconds.
* @param target The object whose property is to be animated. This object should
- * have a public function on it called <code>setName()</code>, where <code>name</code> is
- * the name of the property passed in as the <code>propertyName</code> parameter.
- * @param propertyName The name of the property on the <code>target</code> object
- * that will be animated. Given this name, the constructor will search for a
- * setter on the target object with the name <code>setPropertyName</code>. For example,
- * if the constructor is called with <code>propertyName = "foo"</code>, then the
- * target object should have a setter function with the name <code>setFoo()</code>.
- * @param valueFrom The initial value of the property when the animation begins.
- * @param valueTo The value to which the property will animate.
- */
- public PropertyAnimator(int duration, Object target, String propertyName,
- Object valueFrom, Object valueTo) {
- super(duration, valueFrom, valueTo);
+ * 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 The PropertyValuesHolder objects which hold each the property name and values
+ * to animate that property between.
+ */
+ public PropertyAnimator(long duration, Object target, PropertyValuesHolder...values) {
+ super(duration);
+ setValues(values);
mTarget = target;
- mPropertyName = propertyName;
- }
-
- /**
- * A constructor that takes a single <code>Object</code> value, which is the value that the
- * target object will animate to. When this constructor
- * is called, the system expects to find a setter for <code>propertyName</code> on
- * the target object that takes a value of the same type as the <code>Object</code>s. The
- * system also expects to find a similar getter function with which to derive the starting
- * value for the animation.
- *
- * @param duration The length of the animation, in milliseconds.
- * @param target The object whose property is to be animated. This object should
- * have a public function on it called <code>setName()</code>, where <code>name</code> is
- * the name of the property passed in as the <code>propertyName</code> parameter.
- * @param propertyName The name of the property on the <code>target</code> object
- * that will be animated. Given this name, the constructor will search for a
- * setter on the target object with the name <code>setPropertyName</code>. For example,
- * if the constructor is called with <code>propertyName = "foo"</code>, then the
- * target object should have a setter function with the name <code>setFoo()</code>.
- * @param valueTo The value to which the property will animate.
- */
- public PropertyAnimator(int duration, Object target, String propertyName, Object valueTo) {
- this(duration, target, propertyName, null, valueTo);
- }
-
- /**
- * A constructor that takes <code>Keyframe</code>s. When this constructor
- * is called, the system expects to find a setter for <code>propertyName</code> on
- * the target object that takes a value of the same type as that returned from
- * {@link Keyframe#getType()}.
- * .
- *
- * @param duration The length of the animation, in milliseconds.
- * @param target The object whose property is to be animated. This object should
- * have a public function on it called <code>setName()</code>, where <code>name</code> is
- * the name of the property passed in as the <code>propertyName</code> parameter.
- * @param propertyName The name of the property on the <code>target</code> object
- * that will be animated. Given this name, the constructor will search for a
- * setter on the target object with the name <code>setPropertyName</code>. For example,
- * if the constructor is called with <code>propertyName = "foo"</code>, then the
- * target object should have a setter function with the name <code>setFoo()</code>.
- * @param keyframes The set of keyframes that define the times and values for the animation.
- * These keyframes should be ordered in increasing time value, should have a starting
- * keyframe with a fraction of 0 and and ending keyframe with a fraction of 1.
- */
- public PropertyAnimator(int duration, Object target, String propertyName,
- Keyframe...keyframes) {
- super(duration, keyframes);
- mTarget = target;
- mPropertyName = propertyName;
}
/**
@@ -438,64 +184,8 @@ public final class PropertyAnimator extends Animator {
@Override
void initAnimation() {
super.initAnimation();
- if (mSetter == null) {
- try {
- // 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
- propertyMapLock.writeLock().lock();
- HashMap<String, Method> propertyMap = sSetterPropertyMap.get(mTarget);
- if (propertyMap != null) {
- mSetter = propertyMap.get(mPropertyName);
- }
- if (mSetter == null) {
- mSetter = getPropertyFunction("set", mValueType);
- if (propertyMap == null) {
- propertyMap = new HashMap<String, Method>();
- sSetterPropertyMap.put(mTarget, propertyMap);
- }
- propertyMap.put(mPropertyName, mSetter);
- }
- } finally {
- propertyMapLock.writeLock().unlock();
- }
- }
- if (getKeyframes() == null && (getValueFrom() == null || getValueTo() == null)) {
- // Need to set up the getter if not set by the user, then call it
- // to get the initial values
- if (mGetter == null) {
- try {
- propertyMapLock.writeLock().lock();
- HashMap<String, Method> propertyMap = sGetterPropertyMap.get(mTarget);
- if (propertyMap != null) {
- mGetter = propertyMap.get(mPropertyName);
- }
- if (mGetter == null) {
- mGetter = getPropertyFunction("get", null);
- if (propertyMap == null) {
- propertyMap = new HashMap<String, Method>();
- sGetterPropertyMap.put(mTarget, propertyMap);
- }
- propertyMap.put(mPropertyName, mGetter);
- }
- } finally {
- propertyMapLock.writeLock().unlock();
- }
- }
- try {
- if (getValueFrom() == null) {
- setValueFrom(mGetter.invoke(mTarget));
- }
- if (getValueTo() == null) {
- setValueTo(mGetter.invoke(mTarget));
- }
- } catch (IllegalArgumentException e) {
- Log.e("PropertyAnimator", e.toString());
- } catch (IllegalAccessException e) {
- Log.e("PropertyAnimator", e.toString());
- } catch (InvocationTargetException e) {
- Log.e("PropertyAnimator", e.toString());
- }
+ for (PropertyValuesHolder valuesHolder : mValues.values()) {
+ valuesHolder.setupSetterAndGetter(mTarget);
}
}
@@ -533,23 +223,8 @@ public final class PropertyAnimator extends Animator {
@Override
void animateValue(float fraction) {
super.animateValue(fraction);
- if (mSetter != null) {
- try {
- mTmpValueArray[0] = getAnimatedValue();
- mSetter.invoke(mTarget, mTmpValueArray);
- } catch (InvocationTargetException e) {
- Log.e("PropertyAnimator", e.toString());
- } catch (IllegalAccessException e) {
- Log.e("PropertyAnimator", e.toString());
- }
+ for (PropertyValuesHolder valuesHolder : mValues.values()) {
+ valuesHolder.setAnimatedValue(mTarget);
}
}
-
- @Override
- public String toString() {
- return "Animator: target: " + this.mTarget + "\n" +
- " property: " + mPropertyName + "\n" +
- " from: " + getValueFrom() + "\n" +
- " to: " + getValueTo();
- }
}
diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java
new file mode 100644
index 000000000000..05e0bc108b28
--- /dev/null
+++ b/core/java/android/animation/PropertyValuesHolder.java
@@ -0,0 +1,514 @@
+/*
+ * Copyright (C) 2010 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.animation;
+
+import android.util.Log;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ */
+public class PropertyValuesHolder<T> {
+
+ /**
+ * The name of the property associated with the values. This need not be a real property,
+ * unless this object is being used with PropertyAnimator. But this is the name by which
+ * aniamted values are looked up with getAnimatedValue(String) in Animator.
+ */
+ private String mPropertyName;
+
+ /**
+ * The setter function, if needed. PropertyAnimator hands off this functionality to
+ * PropertyValuesHolder, since it holds all of the per-property information. This
+ * property can be manually set via setSetter(). Otherwise, it is automatically
+ * derived when the animation starts in setupSetterAndGetter() if using PropertyAnimator.
+ */
+ private Method mSetter = null;
+
+ /**
+ * The getter function, if needed. PropertyAnimator hands off this functionality to
+ * PropertyValuesHolder, since it holds all of the per-property information. This
+ * property can be manually set via setSetter(). Otherwise, it is automatically
+ * derived when the animation starts in setupSetterAndGetter() if using PropertyAnimator.
+ * The getter is only derived and used if one of the values is null.
+ */
+ private Method mGetter = null;
+
+ /**
+ * The type of values supplied. This information is used both in deriving the setter/getter
+ * functions and in deriving the type of TypeEvaluator.
+ */
+ private Class mValueType;
+
+ /**
+ * The set of keyframes (time/value pairs) that define this animation.
+ */
+ private KeyframeSet mKeyframeSet = null;
+
+
+ // type evaluators for the three primitive types handled by this implementation
+ private static final TypeEvaluator sIntEvaluator = new IntEvaluator();
+ private static final TypeEvaluator sFloatEvaluator = new FloatEvaluator();
+ private static final TypeEvaluator sDoubleEvaluator = new DoubleEvaluator();
+
+ // We try several different types when searching for appropriate setter/getter functions.
+ // The caller may have supplied values in a type that does not match the setter/getter
+ // functions (such as the integers 0 and 1 to represent floating point values for alpha).
+ // Also, the use of generics in constructors means that we end up with the Object versions
+ // of primitive types (Float vs. float). But most likely, the setter/getter functions
+ // will take primitive types instead.
+ // So we supply an ordered array of other types to try before giving up.
+ private static Class[] FLOAT_VARIANTS = {float.class, Float.class, double.class, int.class,
+ Double.class, Integer.class};
+ private static Class[] INTEGER_VARIANTS = {int.class, Integer.class, float.class, double.class,
+ Float.class, Double.class};
+ private static Class[] DOUBLE_VARIANTS = {double.class, Double.class, float.class, int.class,
+ Float.class, Integer.class};
+
+ // These maps hold all property entries for a particular class. This map
+ // is used to speed up property/setter/getter lookups for a given class/property
+ // combination. No need to use reflection on the combination more than once.
+ private static final HashMap<Class, HashMap<String, Method>> sSetterPropertyMap =
+ new HashMap<Class, HashMap<String, Method>>();
+ private static final HashMap<Class, HashMap<String, Method>> sGetterPropertyMap =
+ new HashMap<Class, HashMap<String, Method>>();
+
+ // This lock is used to ensure that only one thread is accessing the property maps
+ // at a time.
+ private ReentrantReadWriteLock propertyMapLock = new ReentrantReadWriteLock();
+
+ // Used to pass single value to varargs parameter in setter invocation
+ private Object[] mTmpValueArray = new Object[1];
+
+ /**
+ * The type evaluator used to calculate the animated values. This evaluator is determined
+ * automatically based on the type of the start/end objects passed into the constructor,
+ * but the system only knows about the primitive types int, double, and float. Any other
+ * type will need to set the evaluator to a custom evaluator for that type.
+ */
+ private TypeEvaluator mEvaluator;
+
+ /**
+ * The value most recently calculated by calculateValue(). This is set during
+ * that function and might be retrieved later either by Animator.animatedValue() or
+ * by the property-setting logic in PropertyAnimator.animatedValue().
+ */
+ private Object mAnimatedValue;
+
+ /**
+ * Constructs a PropertyValuesHolder object with just a set of values. This constructor
+ * is typically not used when animating objects with PropertyAnimator, because that
+ * object needs distinct and meaningful property names. Simpler animations of one
+ * set of values using Animator may use this constructor, however, because no
+ * distinguishing name is needed.
+ * @param values The set of values to animate between. If there is only one value, it
+ * is assumed to be the final value being animated to, and the initial value will be
+ * derived on the fly.
+ */
+ public PropertyValuesHolder(T...values) {
+ this(null, values);
+ }
+
+ /**
+ * Constructs 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
+ * 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 a getter function
+ * on the object. 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
+ * {@link android.animation.PropertyAnimator}, and with a getter function either
+ * derived automatically from <code>propertyName</code> or set explicitly via
+ * {@link #setGetter(java.lang.reflect.Method)}, since otherwise PropertyValuesHolder has
+ * no way of determining what the value should be.
+ * @param propertyName The name of the property associated with this set of values. This
+ * can be the actual property name to be used when using a PropertyAnimator object, or
+ * just a name used to get animated values, such as if this object is used with an
+ * Animator object.
+ * @param values The set of values to animate between.
+ */
+ public PropertyValuesHolder(String propertyName, T... values) {
+ mPropertyName = propertyName;
+ setValues(values);
+ }
+
+ /**
+ * Sets the values being animated between.
+ * 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
+ * on the object. 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
+ * {@link android.animation.PropertyAnimator}, and with a getter function either
+ * derived automatically from <code>propertyName</code> or set explicitly via
+ * {@link #setGetter(java.lang.reflect.Method)}, since otherwise PropertyValuesHolder has
+ * no way of determining what the value should be.
+ * @param values The set of values to animate between.
+ */
+ public void setValues(T... values) {
+ int numKeyframes = values.length;
+ for (int i = 0; i < numKeyframes; ++i) {
+ if (values[i] != null) {
+ Class thisValueType = values[i].getClass();
+ if (mValueType == null) {
+ mValueType = thisValueType;
+ } else {
+ if (thisValueType != mValueType) {
+ if (mValueType == Integer.class &&
+ (thisValueType == Float.class || thisValueType == Double.class)) {
+ mValueType = thisValueType;
+ } else if (mValueType == Float.class && thisValueType == Double.class) {
+ mValueType = thisValueType;
+ }
+ }
+ }
+ }
+ }
+ Keyframe keyframes[] = new Keyframe[Math.max(numKeyframes,2)];
+ if (mValueType.equals(Keyframe.class)) {
+ mValueType = ((Keyframe)values[0]).getType();
+ for (int i = 0; i < numKeyframes; ++i) {
+ keyframes[i] = (Keyframe)values[i];
+ }
+ } else {
+ if (numKeyframes == 1) {
+ keyframes[0] = new Keyframe(0f, null);
+ keyframes[1] = new Keyframe(1f, values[0]);
+ } else {
+ keyframes[0] = new Keyframe(0f, values[0]);
+ for (int i = 1; i < numKeyframes; ++i) {
+ if (values[i] != null && (values[i].getClass() != mValueType)) {
+
+ }
+ keyframes[i] = new Keyframe((float) i / (numKeyframes - 1), values[i]);
+ }
+ }
+ }
+ mKeyframeSet = new KeyframeSet(keyframes);
+ }
+
+
+
+ /**
+ * 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 targetClass The class to search for the method
+ * @param prefix "set" or "get", depending on whether we need a setter or getter.
+ * @param valueType The type of the parameter (in the case of a setter). This type
+ * is derived from the values set on this PropertyValuesHolder. This type is used as
+ * a first guess at the parameter type, but we check for methods with several different
+ * types to avoid problems with slight mis-matches between supplied values and actual
+ * value types used on the setter.
+ * @return Method the method associated with mPropertyName.
+ */
+ private Method getPropertyFunction(Class targetClass, 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 methodName = prefix + firstLetter + theRest;
+ Class args[] = null;
+ if (valueType == null) {
+ try {
+ returnVal = targetClass.getMethod(methodName, args);
+ } catch (NoSuchMethodException e) {
+ Log.e("PropertyValuesHolder",
+ "Couldn't find no-arg method for property " + mPropertyName + ": " + e);
+ }
+ } else {
+ args = new Class[1];
+ Class typeVariants[];
+ if (mValueType.equals(Float.class)) {
+ typeVariants = FLOAT_VARIANTS;
+ } else if (mValueType.equals(Integer.class)) {
+ typeVariants = INTEGER_VARIANTS;
+ } else if (mValueType.equals(Double.class)) {
+ typeVariants = DOUBLE_VARIANTS;
+ } else {
+ typeVariants = new Class[1];
+ typeVariants[0] = mValueType;
+ }
+ for (Class typeVariant : typeVariants) {
+ args[0] = typeVariant;
+ try {
+ returnVal = targetClass.getMethod(methodName, args);
+ return returnVal;
+ } catch (NoSuchMethodException e) {
+ // Swallow the error and keep trying other variants
+ }
+ }
+ }
+ // If we got here, then no appropriate function was found
+ Log.e("PropertyValuesHolder",
+ "Couldn't find setter/getter for property " + mPropertyName +
+ "with value type "+ mValueType);
+ return returnVal;
+ }
+
+
+ /**
+ * Returns the setter or getter requested. This utility function checks whether the
+ * requested method exists in the propertyMapMap cache. If not, it calls another
+ * utility function to request the Method from the targetClass directly.
+ * @param targetClass The Class on which the requested method should exist.
+ * @param propertyMapMap The cache of setters/getters derived so far.
+ * @param prefix "set" or "get", for the setter or getter.
+ * @param valueType The type of parameter passed into the method (null for getter).
+ * @return Method the method associated with mPropertyName.
+ */
+ private Method setupSetterOrGetter(Class targetClass,
+ HashMap<Class, HashMap<String, Method>> propertyMapMap,
+ String prefix, Class valueType) {
+ Method setterOrGetter = null;
+ try {
+ // 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?
+ propertyMapLock.writeLock().lock();
+ HashMap<String, Method> propertyMap = propertyMapMap.get(targetClass);
+ if (propertyMap != null) {
+ setterOrGetter = propertyMap.get(mPropertyName);
+ }
+ if (setterOrGetter == null) {
+ setterOrGetter = getPropertyFunction(targetClass, prefix, valueType);
+ if (propertyMap == null) {
+ propertyMap = new HashMap<String, Method>();
+ propertyMapMap.put(targetClass, propertyMap);
+ }
+ propertyMap.put(mPropertyName, setterOrGetter);
+ }
+ } finally {
+ propertyMapLock.writeLock().unlock();
+ }
+ return setterOrGetter;
+ }
+
+ /**
+ * Utility function to get the setter from targetClass
+ * @param targetClass The Class on which the requested method should exist.
+ */
+ private void setupSetter(Class targetClass) {
+ mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", mValueType);
+ }
+
+ /**
+ * Utility function to get the getter from targetClass
+ */
+ private void setupGetter(Class targetClass) {
+ mGetter = setupSetterOrGetter(targetClass, sGetterPropertyMap, "get", null);
+ }
+
+ /**
+ * Internal function (called from PropertyAnimator) to set up the setter and getter
+ * prior to running the animation. If the setter has not been manually set for this
+ * object, it will be derived automatically given the property name, target object, and
+ * types of values supplied. If no getter has been set, it will be supplied iff any of the
+ * supplied values was null. If there is a null value, then the getter (supplied or derived)
+ * will be called to set those null values to the current value of the property
+ * on the target object.
+ * @param target The object on which the setter (and possibly getter) exist.
+ */
+ void setupSetterAndGetter(Object target) {
+ Class targetClass = target.getClass();
+ if (mSetter == null) {
+ setupSetter(targetClass);
+ }
+ for (Keyframe kf : mKeyframeSet.mKeyframes) {
+ if (kf.getValue() == null) {
+ if (mGetter == null) {
+ setupGetter(targetClass);
+ }
+ try {
+ kf.setValue((T) mGetter.invoke(target));
+ } catch (InvocationTargetException e) {
+ Log.e("PropertyValuesHolder", e.toString());
+ } catch (IllegalAccessException e) {
+ Log.e("PropertyValuesHolder", e.toString());
+ }
+ }
+ }
+ }
+
+ /**
+ * Internal function to set the value on the target object, using the setter set up
+ * earlier on this PropertyValuesHolder object. This function is called by PropertyAnimator
+ * to handle turning the value calculated by Animator into a value set on the object
+ * according to the name of the property.
+ * @param target The target object on which the value is set
+ */
+ void setAnimatedValue(Object target) {
+ if (mSetter != null) {
+ try {
+ mTmpValueArray[0] = mAnimatedValue;
+ mSetter.invoke(target, mTmpValueArray);
+ } catch (InvocationTargetException e) {
+ Log.e("PropertyValuesHolder", e.toString());
+ } catch (IllegalAccessException e) {
+ Log.e("PropertyValuesHolder", e.toString());
+ }
+ }
+ }
+
+ /**
+ * Internal function, called by Animator, to set up the TypeEvaluator that will be used
+ * to calculate animated values.
+ */
+ void init() {
+ if (mEvaluator == null) {
+ mEvaluator = (mValueType == int.class) ? sIntEvaluator :
+ (mValueType == double.class) ? sDoubleEvaluator : sFloatEvaluator;
+ }
+ }
+
+ /**
+ * The TypeEvaluator will the automatically determined based on the type of values
+ * supplied to PropertyValuesHolder. The evaluator can be manually set, however, if so
+ * desired. This may be important in cases where either the type of the values supplied
+ * do not match the way that they should be interpolated between, or if the values
+ * are of a custom type or one not currently understood by the animation system. Currently,
+ * only values of type float, double, and int (and their Object equivalents, Float, Double,
+ * and Integer) are correctly interpolated; all other types require setting a TypeEvaluator.
+ * @param evaluator
+ */
+ public void setEvaluator(TypeEvaluator evaluator) {
+ mEvaluator = evaluator;
+ }
+
+ /**
+ * Function used to calculate the value according to the evaluator set up for
+ * this PropertyValuesHolder object. This function is called by Animator.animateValue().
+ *
+ * @param fraction The elapsed, interpolated fraction of the animation.
+ * @return The calculated value at this point in the animation.
+ */
+ Object calculateValue(float fraction) {
+ mAnimatedValue = mKeyframeSet.getValue(fraction, mEvaluator);
+ return mAnimatedValue;
+ }
+
+ /**
+ * Sets the <code>Method</code> that is called with the animated values calculated
+ * during the animation. Setting the setter method is an alternative to supplying a
+ * {@link #setPropertyName(String) propertyName} from which the method is derived. This
+ * approach is more direct, and is especially useful when a function must be called that does
+ * not correspond to the convention of <code>setName()</code>. For example, if a function
+ * called <code>offset()</code> is to be called with the animated values, there is no way
+ * to tell <code>PropertyAnimator</code> how to call that function simply through a property
+ * name, so a setter method should be supplied instead.
+ *
+ * <p>Note that the setter function must take the same parameter type as the
+ * <code>valueFrom</code> and <code>valueTo</code> properties, otherwise the call to
+ * the setter function will fail.</p>
+ *
+ * @param setter The setter method that should be called with the animated values.
+ */
+ public void setSetter(Method setter) {
+ mSetter = setter;
+ }
+
+ /**
+ * Gets the <code>Method</code> that is called with the animated values calculated
+ * during the animation.
+ */
+ public Method getSetter() {
+ return mSetter;
+ }
+
+ /**
+ * Sets the <code>Method</code> that is called to get unsupplied <code>valueFrom</code> or
+ * <code>valueTo</code> properties. Setting the getter method is an alternative to supplying a
+ * {@link #setPropertyName(String) propertyName} from which the method is derived. This
+ * approach is more direct, and is especially useful when a function must be called that does
+ * not correspond to the convention of <code>setName()</code>. For example, if a function
+ * called <code>offset()</code> is to be called to get an initial value, there is no way
+ * to tell <code>PropertyAnimator</code> how to call that function simply through a property
+ * name, so a getter method should be supplied instead.
+ *
+ * <p>Note that the getter method is only called whether supplied here or derived
+ * from the property name, if one of <code>valueFrom</code> or <code>valueTo</code> are
+ * null. If both of those values are non-null, then there is no need to get one of the
+ * values and the getter is not called.
+ *
+ * <p>Note that the getter function must return the same parameter type as the
+ * <code>valueFrom</code> and <code>valueTo</code> properties (whichever of them are
+ * non-null), otherwise the call to the getter function will fail.</p>
+ *
+ * @param getter The getter method that should be called to get initial animation values.
+ */
+ public void setGetter(Method getter) {
+ mGetter = getter;
+ }
+
+ /**
+ * Gets the <code>Method</code> that is called to get unsupplied <code>valueFrom</code> or
+ * <code>valueTo</code> properties.
+ */
+ public Method getGetter() {
+ return mGetter;
+ }
+
+ /**
+ * 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.
+ * For example, a property name of <code>foo</code> will result
+ * in a call to the function <code>setFoo()</code> on the target object. If either
+ * <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will
+ * also be derived and called.
+ *
+ * <p>Note that the setter function derived from this property name
+ * must take the same parameter type as the
+ * <code>valueFrom</code> and <code>valueTo</code> properties, otherwise the call to
+ * the setter function will fail.</p>
+ *
+ * @param propertyName The name of the property being animated.
+ */
+ public void setPropertyName(String propertyName) {
+ mPropertyName = propertyName;
+ }
+
+ /**
+ * 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
+ * in a call to the function <code>setFoo()</code> on the target object. If either
+ * <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will
+ * also be derived and called.
+ */
+ public String getPropertyName() {
+ return mPropertyName;
+ }
+
+ /**
+ * Internal function, called by Animator and PropertyAnimator, to retrieve the value
+ * most recently calculated in calculateValue().
+ * @return
+ */
+ Object getAnimatedValue() {
+ return mAnimatedValue;
+ }
+} \ No newline at end of file