Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 16d2c9cc authored by George Mount's avatar George Mount
Browse files

Setter values can now have different type than animated values.

Add TypeConverter to convert animated values type to target
setter type.

Change-Id: I7f0581b18a5321b4aafd7e47f147a81573c45061
parent 7235ae06
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -2512,6 +2512,7 @@ package android.animation {
    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);
@@ -2529,6 +2530,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>, 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...);
@@ -2556,6 +2559,12 @@ package android.animation {
    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);
  }
@@ -31782,8 +31791,6 @@ package android.widget {
    ctor public NumberPicker(android.content.Context, android.util.AttributeSet);
    ctor public NumberPicker(android.content.Context, android.util.AttributeSet, int);
    ctor public NumberPicker(android.content.Context, android.util.AttributeSet, int, int);
    method public int computeVerticalScrollOffset();
    method public int computeVerticalScrollRange();
    method public java.lang.String[] getDisplayedValues();
    method public int getMaxValue();
    method public int getMinValue();
+32 −6
Original line number Diff line number Diff line
@@ -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 <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
+77 −14
Original line number Diff line number Diff line
@@ -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 <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
@@ -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);
                    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);
    }

    /**
+68 −0
Original line number Diff line number Diff line
/*
 * 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;
    }
}