Merge "Setter values can now have different type than animated values."
diff --git a/api/current.txt b/api/current.txt
index 619b4e8..7744752 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2521,6 +2521,7 @@
method public static android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, int...);
method public static android.animation.ObjectAnimator ofObject(java.lang.Object, java.lang.String, android.animation.TypeEvaluator, java.lang.Object...);
method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeEvaluator<V>, V...);
+ method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, P>, android.animation.TypeConverter<V, P>, android.animation.TypeEvaluator<V>, V...);
method public static android.animation.ObjectAnimator ofPropertyValuesHolder(java.lang.Object, android.animation.PropertyValuesHolder...);
method public void setAutoCancel(boolean);
method public void setProperty(android.util.Property);
@@ -2538,6 +2539,8 @@
method public static android.animation.PropertyValuesHolder ofKeyframe(android.util.Property, android.animation.Keyframe...);
method public static android.animation.PropertyValuesHolder ofObject(java.lang.String, android.animation.TypeEvaluator, java.lang.Object...);
method public static android.animation.PropertyValuesHolder ofObject(android.util.Property, android.animation.TypeEvaluator<V>, V...);
+ method public static android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<T, V>, android.animation.TypeEvaluator<T>, T...);
+ method public void setConverter(android.animation.TypeConverter);
method public void setEvaluator(android.animation.TypeEvaluator);
method public void setFloatValues(float...);
method public void setIntValues(int...);
@@ -2566,6 +2569,12 @@
method public abstract float getInterpolation(float);
}
+ public abstract class TypeConverter {
+ ctor public TypeConverter(java.lang.Class<T>, java.lang.Class<V>);
+ method public abstract V convert(T);
+ method public T convertBack(V);
+ }
+
public abstract interface TypeEvaluator {
method public abstract T evaluate(float, T, T);
}
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index 9c88ccf..f930f22 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -191,7 +191,7 @@
/**
* 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
+ * value implies that that value is the one being animated to. Two values imply 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).
@@ -211,7 +211,7 @@
/**
* 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
+ * value implies that that value is the one being animated to. Two values imply 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).
@@ -229,7 +229,7 @@
/**
* 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
+ * value implies that that value is the one being animated to. Two values imply 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).
@@ -249,7 +249,7 @@
/**
* 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
+ * value implies that that value is the one being animated to. Two values imply 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).
@@ -268,7 +268,7 @@
/**
* 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
+ * value implies that that value is the one being animated to. Two values imply 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).
@@ -293,7 +293,7 @@
/**
* 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
+ * value implies that that value is the one being animated to. Two values imply 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).
@@ -315,6 +315,32 @@
}
/**
+ * 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 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). This variant supplies a <code>TypeConverter</code> to
+ * convert from the animated values to the type of the property. If only one value is
+ * supplied, the <code>TypeConverter</code> must implement
+ * {@link TypeConverter#convertBack(Object)} to retrieve the current value.
+ *
+ * @param target The object whose property is to be animated.
+ * @param property The property being animated.
+ * @param converter Converts the animated object to the Property type.
+ * @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, P> ObjectAnimator ofObject(T target, Property<T, P> property,
+ TypeConverter<V, P> converter, TypeEvaluator<V> evaluator, V... values) {
+ PropertyValuesHolder pvh = PropertyValuesHolder.ofObject(property, converter, evaluator,
+ values);
+ return ofPropertyValuesHolder(target, pvh);
+ }
+
+ /**
* 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
diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java
index 43014ad..5f5e485 100644
--- a/core/java/android/animation/PropertyValuesHolder.java
+++ b/core/java/android/animation/PropertyValuesHolder.java
@@ -124,6 +124,11 @@
private Object mAnimatedValue;
/**
+ * Converts from the source Object type to the setter Object type.
+ */
+ private TypeConverter mConverter;
+
+ /**
* Internal utility constructor, used by the factory methods to set the property name.
* @param propertyName The name of the property for this holder.
*/
@@ -227,6 +232,34 @@
}
/**
+ * 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. This variant also
+ * takes a <code>TypeConverter</code> to convert from animated values to the type
+ * of the property. If only one value is supplied, the <code>TypeConverter</code>
+ * must implement {@link TypeConverter#convertBack(Object)} to retrieve the current
+ * value.
+ *
+ * @param property The property being animated. Should not be null.
+ * @param converter Converts the animated object to the Property type.
+ * @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.
+ * @see #setConverter(TypeConverter)
+ * @see TypeConverter
+ */
+ public static <T, V> PropertyValuesHolder ofObject(Property<?, V> property,
+ TypeConverter<T, V> converter, TypeEvaluator<T> evaluator, T... values) {
+ PropertyValuesHolder pvh = new PropertyValuesHolder(property);
+ pvh.setConverter(converter);
+ 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
@@ -361,6 +394,14 @@
}
/**
+ * Sets the converter to convert from the values type to the setter's parameter type.
+ * @param converter The converter to use to convert values.
+ */
+ public void setConverter(TypeConverter converter) {
+ mConverter = converter;
+ }
+
+ /**
* 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
@@ -389,22 +430,24 @@
} else {
args = new Class[1];
Class typeVariants[];
- if (mValueType.equals(Float.class)) {
+ if (valueType.equals(Float.class)) {
typeVariants = FLOAT_VARIANTS;
- } else if (mValueType.equals(Integer.class)) {
+ } else if (valueType.equals(Integer.class)) {
typeVariants = INTEGER_VARIANTS;
- } else if (mValueType.equals(Double.class)) {
+ } else if (valueType.equals(Double.class)) {
typeVariants = DOUBLE_VARIANTS;
} else {
typeVariants = new Class[1];
- typeVariants[0] = mValueType;
+ typeVariants[0] = valueType;
}
for (Class typeVariant : typeVariants) {
args[0] = typeVariant;
try {
returnVal = targetClass.getMethod(methodName, args);
- // change the value type to suit
- mValueType = typeVariant;
+ if (mConverter == null) {
+ // change the value type to suit
+ mValueType = typeVariant;
+ }
return returnVal;
} catch (NoSuchMethodException e) {
// Swallow the error and keep trying other variants
@@ -415,7 +458,7 @@
if (returnVal == null) {
Log.w("PropertyValuesHolder", "Method " +
- getMethodName(prefix, mPropertyName) + "() with type " + mValueType +
+ getMethodName(prefix, mPropertyName) + "() with type " + valueType +
" not found on target class " + targetClass);
}
@@ -465,7 +508,8 @@
* @param targetClass The Class on which the requested method should exist.
*/
void setupSetter(Class targetClass) {
- mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", mValueType);
+ Class<?> propertyType = mConverter == null ? mValueType : mConverter.getTargetType();
+ mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", propertyType);
}
/**
@@ -489,10 +533,13 @@
if (mProperty != null) {
// check to make sure that mProperty is on the class of target
try {
- Object testValue = mProperty.get(target);
+ Object testValue = null;
for (Keyframe kf : mKeyframeSet.mKeyframes) {
if (!kf.hasValue()) {
- kf.setValue(mProperty.get(target));
+ if (testValue == null) {
+ testValue = convertBack(mProperty.get(target));
+ }
+ kf.setValue(testValue);
}
}
return;
@@ -516,7 +563,8 @@
}
}
try {
- kf.setValue(mGetter.invoke(target));
+ Object value = convertBack(mGetter.invoke(target));
+ kf.setValue(value);
} catch (InvocationTargetException e) {
Log.e("PropertyValuesHolder", e.toString());
} catch (IllegalAccessException e) {
@@ -526,6 +574,18 @@
}
}
+ private Object convertBack(Object value) {
+ if (mConverter != null) {
+ value = mConverter.convertBack(value);
+ if (value == null) {
+ throw new IllegalArgumentException("Converter "
+ + mConverter.getClass().getName()
+ + " must implement convertBack and not return null.");
+ }
+ }
+ return value;
+ }
+
/**
* Utility function to set the value stored in a particular Keyframe. The value used is
* whatever the value is for the property name specified in the keyframe on the target object.
@@ -535,7 +595,8 @@
*/
private void setupValue(Object target, Keyframe kf) {
if (mProperty != null) {
- kf.setValue(mProperty.get(target));
+ Object value = convertBack(mProperty.get(target));
+ kf.setValue(value);
}
try {
if (mGetter == null) {
@@ -546,7 +607,8 @@
return;
}
}
- kf.setValue(mGetter.invoke(target));
+ Object value = convertBack(mGetter.invoke(target));
+ kf.setValue(value);
} catch (InvocationTargetException e) {
Log.e("PropertyValuesHolder", e.toString());
} catch (IllegalAccessException e) {
@@ -657,7 +719,8 @@
* @param fraction The elapsed, interpolated fraction of the animation.
*/
void calculateValue(float fraction) {
- mAnimatedValue = mKeyframeSet.getValue(fraction);
+ Object value = mKeyframeSet.getValue(fraction);
+ mAnimatedValue = mConverter == null ? value : mConverter.convert(value);
}
/**
diff --git a/core/java/android/animation/TypeConverter.java b/core/java/android/animation/TypeConverter.java
new file mode 100644
index 0000000..03b3eb5
--- /dev/null
+++ b/core/java/android/animation/TypeConverter.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2013 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;
+
+/**
+ * Abstract base class used convert type T to another type V. This
+ * is necessary when the value types of in animation are different
+ * from the property type.
+ * @see PropertyValuesHolder#setConverter(TypeConverter)
+ */
+public abstract class TypeConverter<T, V> {
+ private Class<T> mFromClass;
+ private Class<V> mToClass;
+
+ public TypeConverter(Class<T> fromClass, Class<V> toClass) {
+ mFromClass = fromClass;
+ mToClass = toClass;
+ }
+
+ /**
+ * Returns the target converted type. Used by the animation system to determine
+ * the proper setter function to call.
+ * @return The Class to convert the input to.
+ */
+ Class<V> getTargetType() {
+ return mToClass;
+ }
+
+ /**
+ * Returns the source conversion type.
+ */
+ Class<T> getSourceType() {
+ return mFromClass;
+ }
+
+ /**
+ * Converts a value from one type to another.
+ * @param value The Object to convert.
+ * @return A value of type V, converted from <code>value</code>.
+ */
+ public abstract V convert(T value);
+
+ /**
+ * Does a conversion from the target type back to the source type. The subclass
+ * must implement this when a TypeConverter is used in animations and current
+ * values will need to be read for an animation. By default, this will return null,
+ * indicating that back-conversion is not supported.
+ * @param value The Object to convert.
+ * @return A value of type T, converted from <code>value</code>.
+ */
+ public T convertBack(V value) {
+ return null;
+ }
+}