diff --git a/api/current.txt b/api/current.txt index 619b4e88413d7..7744752b40aa7 100644 --- a/api/current.txt +++ b/api/current.txt @@ -2521,6 +2521,7 @@ package android.animation { method public static android.animation.ObjectAnimator ofInt(T, android.util.Property, 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, android.animation.TypeEvaluator, V...); + method public static android.animation.ObjectAnimator ofObject(T, android.util.Property, android.animation.TypeConverter, android.animation.TypeEvaluator, 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 @@ package android.animation { 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...); + method public static android.animation.PropertyValuesHolder ofObject(android.util.Property, android.animation.TypeConverter, android.animation.TypeEvaluator, 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 @@ package android.animation { method public abstract float getInterpolation(float); } + public abstract class TypeConverter { + ctor public TypeConverter(java.lang.Class, java.lang.Class); + 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 9c88ccf32d412..f930f2259a9b1 100644 --- a/core/java/android/animation/ObjectAnimator.java +++ b/core/java/android/animation/ObjectAnimator.java @@ -191,7 +191,7 @@ 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 + * 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 @@ 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 + * 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 @@ public final class ObjectAnimator extends ValueAnimator { /** * 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 @@ public final class ObjectAnimator extends ValueAnimator { /** * 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 @@ public final class ObjectAnimator extends ValueAnimator { /** * 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 @@ public final class ObjectAnimator extends ValueAnimator { /** * 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). @@ -314,6 +314,32 @@ public final class ObjectAnimator extends ValueAnimator { 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 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 TypeConverter to + * convert from the animated values to the type of the property. If only one value is + * supplied, the TypeConverter 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 ObjectAnimator ofObject(T target, Property property, + TypeConverter converter, TypeEvaluator 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 PropertyValueHolder objects. This variant should be used when animating diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java index 43014adc53003..5f5e48584c338 100644 --- a/core/java/android/animation/PropertyValuesHolder.java +++ b/core/java/android/animation/PropertyValuesHolder.java @@ -123,6 +123,11 @@ public class PropertyValuesHolder implements Cloneable { */ 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. @@ -226,6 +231,34 @@ public class PropertyValuesHolder implements Cloneable { return pvh; } + /** + * 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 TypeConverter to convert from animated values to the type + * of the property. If only one value is supplied, the TypeConverter + * 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 PropertyValuesHolder ofObject(Property property, + TypeConverter converter, TypeEvaluator 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 @@ -360,6 +393,14 @@ public class PropertyValuesHolder implements Cloneable { mKeyframeSet = KeyframeSet.ofObject(values); } + /** + * 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 @@ -389,22 +430,24 @@ public class PropertyValuesHolder implements Cloneable { } 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 @@ public class PropertyValuesHolder implements Cloneable { 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 @@ public class PropertyValuesHolder implements Cloneable { * @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 @@ public class PropertyValuesHolder implements Cloneable { 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 @@ public class PropertyValuesHolder implements Cloneable { } } 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 @@ public class PropertyValuesHolder implements Cloneable { } } + 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 @@ public class PropertyValuesHolder implements Cloneable { */ 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 @@ public class PropertyValuesHolder implements Cloneable { 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 @@ public class PropertyValuesHolder implements Cloneable { * @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 0000000000000..03b3eb5aa0655 --- /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 { + private Class mFromClass; + private Class mToClass; + + public TypeConverter(Class fromClass, Class 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 getTargetType() { + return mToClass; + } + + /** + * Returns the source conversion type. + */ + Class 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 value. + */ + 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 value. + */ + public T convertBack(V value) { + return null; + } +}