Support for multiple value animations.

Bug 2805977
Support for multi-value setters in ObjectAnimator.

Change-Id: I7854dfcb82372afc6d9afb4c50a289ff9d41574e
This commit is contained in:
George Mount
2013-08-30 13:56:01 -07:00
parent 16d2c9cc6b
commit 4eed52944c
6 changed files with 740 additions and 1 deletions

View File

@@ -2433,11 +2433,23 @@ package android.animation {
method public java.lang.Object evaluate(float, java.lang.Object, java.lang.Object);
}
public class FloatArrayEvaluator implements android.animation.TypeEvaluator {
ctor public FloatArrayEvaluator();
ctor public FloatArrayEvaluator(float[]);
method public float[] evaluate(float, float[], float[]);
}
public class FloatEvaluator implements android.animation.TypeEvaluator {
ctor public FloatEvaluator();
method public java.lang.Float evaluate(float, java.lang.Number, java.lang.Number);
}
public class IntArrayEvaluator implements android.animation.TypeEvaluator {
ctor public IntArrayEvaluator();
ctor public IntArrayEvaluator(int[]);
method public int[] evaluate(float, int[], int[]);
}
public class IntEvaluator implements android.animation.TypeEvaluator {
ctor public IntEvaluator();
method public java.lang.Integer evaluate(float, java.lang.Integer, java.lang.Integer);
@@ -2510,6 +2522,10 @@ package android.animation {
method public static android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, float...);
method public static android.animation.ObjectAnimator ofInt(java.lang.Object, java.lang.String, int...);
method public static android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, int...);
method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, float[][]);
method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, T...);
method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, int[][]);
method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, T...);
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...);
@@ -2528,6 +2544,12 @@ package android.animation {
method public static android.animation.PropertyValuesHolder ofInt(android.util.Property<?, java.lang.Integer>, int...);
method public static android.animation.PropertyValuesHolder ofKeyframe(java.lang.String, android.animation.Keyframe...);
method public static android.animation.PropertyValuesHolder ofKeyframe(android.util.Property, android.animation.Keyframe...);
method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, float[][]);
method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<V, float[]>, android.animation.TypeEvaluator<V>, V...);
method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, int[][]);
method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<V, int[]>, android.animation.TypeEvaluator<V>, V...);
method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, 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...);

View File

@@ -0,0 +1,77 @@
/*
* 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;
/**
* This evaluator can be used to perform type interpolation between <code>float[]</code> values.
* Each index into the array is treated as a separate value to interpolate. For example,
* evaluating <code>{100, 200}</code> and <code>{300, 400}</code> will interpolate the value at
* the first index between 100 and 300 and the value at the second index value between 200 and 400.
*/
public class FloatArrayEvaluator implements TypeEvaluator<float[]> {
private float[] mArray;
/**
* Create a FloatArrayEvaluator that does not reuse the animated value. Care must be taken
* when using this option because on every evaluation a new <code>float[]</code> will be
* allocated.
*
* @see #FloatArrayEvaluator(float[])
*/
public FloatArrayEvaluator() {
}
/**
* Create a FloatArrayEvaluator that reuses <code>reuseArray</code> for every evaluate() call.
* Caution must be taken to ensure that the value returned from
* {@link android.animation.ValueAnimator#getAnimatedValue()} is not cached, modified, or
* used across threads. The value will be modified on each <code>evaluate()</code> call.
*
* @param reuseArray The array to modify and return from <code>evaluate</code>.
*/
public FloatArrayEvaluator(float[] reuseArray) {
mArray = reuseArray;
}
/**
* Interpolates the value at each index by the fraction. If
* {@link #FloatArrayEvaluator(float[])} was used to construct this object,
* <code>reuseArray</code> will be returned, otherwise a new <code>float[]</code>
* will be returned.
*
* @param fraction The fraction from the starting to the ending values
* @param startValue The start value.
* @param endValue The end value.
* @return A <code>float[]</code> where each element is an interpolation between
* the same index in startValue and endValue.
*/
@Override
public float[] evaluate(float fraction, float[] startValue, float[] endValue) {
float[] array = mArray;
if (array == null) {
array = new float[startValue.length];
}
for (int i = 0; i < array.length; i++) {
float start = startValue[i];
float end = endValue[i];
array[i] = start + (fraction * (end - start));
}
return array;
}
}

View File

@@ -0,0 +1,75 @@
/*
* 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;
/**
* This evaluator can be used to perform type interpolation between <code>int[]</code> values.
* Each index into the array is treated as a separate value to interpolate. For example,
* evaluating <code>{100, 200}</code> and <code>{300, 400}</code> will interpolate the value at
* the first index between 100 and 300 and the value at the second index value between 200 and 400.
*/
public class IntArrayEvaluator implements TypeEvaluator<int[]> {
private int[] mArray;
/**
* Create an IntArrayEvaluator that does not reuse the animated value. Care must be taken
* when using this option because on every evaluation a new <code>int[]</code> will be
* allocated.
*
* @see #IntArrayEvaluator(int[])
*/
public IntArrayEvaluator() {
}
/**
* Create an IntArrayEvaluator that reuses <code>reuseArray</code> for every evaluate() call.
* Caution must be taken to ensure that the value returned from
* {@link android.animation.ValueAnimator#getAnimatedValue()} is not cached, modified, or
* used across threads. The value will be modified on each <code>evaluate()</code> call.
*
* @param reuseArray The array to modify and return from <code>evaluate</code>.
*/
public IntArrayEvaluator(int[] reuseArray) {
mArray = reuseArray;
}
/**
* Interpolates the value at each index by the fraction. If {@link #IntArrayEvaluator(int[])}
* was used to construct this object, <code>reuseArray</code> will be returned, otherwise
* a new <code>int[]</code> will be returned.
*
* @param fraction The fraction from the starting to the ending values
* @param startValue The start value.
* @param endValue The end value.
* @return An <code>int[]</code> where each element is an interpolation between
* the same index in startValue and endValue.
*/
@Override
public int[] evaluate(float fraction, int[] startValue, int[] endValue) {
int[] array = mArray;
if (array == null) {
array = new int[startValue.length];
}
for (int i = 0; i < array.length; i++) {
int start = startValue[i];
int end = endValue[i];
array[i] = (int) (start + (fraction * (end - start)));
}
return array;
}
}

View File

@@ -227,6 +227,53 @@ public final class ObjectAnimator extends ValueAnimator {
return anim;
}
/**
* Constructs and returns an ObjectAnimator that animates over int values for a multiple
* parameters setter. Only public methods that take only int parameters are supported.
* Each <code>int[]</code> contains a complete set of parameters to the setter method.
* At least two <code>int[]</code> values must be provided, a start and end. More than two
* values imply a starting value, values to animate through along the way, and an ending
* value (these values will be distributed evenly across the duration of the animation).
*
* @param target The object whose property is to be animated. This object may
* have a public method on it called <code>setName()</code>, where <code>name</code> is
* the value of the <code>propertyName</code> parameter. <code>propertyName</code> may also
* be the case-sensitive complete name of the public setter method.
* @param propertyName The name of the property being animated or the name of the setter method.
* @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 ofMultiInt(Object target, String propertyName, int[][] values) {
PropertyValuesHolder pvh = PropertyValuesHolder.ofMultiInt(propertyName, values);
return ofPropertyValuesHolder(target, pvh);
}
/**
* Constructs and returns an ObjectAnimator that animates over values for a multiple int
* parameters setter. Only public methods that take only int parameters are supported.
* <p>At least two values must be provided, a start and end. 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).</p>
*
* @param target The object whose property is to be animated. This object may
* have a public method on it called <code>setName()</code>, where <code>name</code> is
* the value of the <code>propertyName</code> parameter. <code>propertyName</code> may also
* be the complete name of the public method.
* @param propertyName The name of the property being animated or the name of the setter method.
* @param converter Converts T objects into int parameters for the multi-value setter.
* @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> ObjectAnimator ofMultiInt(Object target, String propertyName,
TypeConverter<T, int[]> converter, TypeEvaluator<T> evaluator, T... values) {
PropertyValuesHolder pvh = PropertyValuesHolder.ofMultiInt(propertyName, converter,
evaluator, values);
return ObjectAnimator.ofPropertyValuesHolder(target, pvh);
}
/**
* 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 starting
@@ -266,6 +313,54 @@ public final class ObjectAnimator extends ValueAnimator {
return anim;
}
/**
* Constructs and returns an ObjectAnimator that animates over float values for a multiple
* parameters setter. Only public methods that take only float parameters are supported.
* Each <code>float[]</code> contains a complete set of parameters to the setter method.
* At least two <code>float[]</code> values must be provided, a start and end. More than two
* values imply a starting value, values to animate through along the way, and an ending
* value (these values will be distributed evenly across the duration of the animation).
*
* @param target The object whose property is to be animated. This object may
* have a public method on it called <code>setName()</code>, where <code>name</code> is
* the value of the <code>propertyName</code> parameter. <code>propertyName</code> may also
* be the complete name of the public method.
* @param propertyName The name of the property being animated or the name of the setter method.
* @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 ofMultiFloat(Object target, String propertyName,
float[][] values) {
PropertyValuesHolder pvh = PropertyValuesHolder.ofMultiFloat(propertyName, values);
return ofPropertyValuesHolder(target, pvh);
}
/**
* Constructs and returns an ObjectAnimator that animates over values for a multiple float
* parameters setter. Only public methods that take only float parameters are supported.
* <p>At least two values must be provided, a start and end. 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).</p>
*
* @param target The object whose property is to be animated. This object may
* have a public method on it called <code>setName()</code>, where <code>name</code> is
* the value of the <code>propertyName</code> parameter. <code>propertyName</code> may also
* be the case-sensitive complete name of the public setter method.
* @param propertyName The name of the property being animated or the name of the setter method.
* @param converter Converts T objects into float parameters for the multi-value setter.
* @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> ObjectAnimator ofMultiFloat(Object target, String propertyName,
TypeConverter<T, float[]> converter, TypeEvaluator<T> evaluator, T... values) {
PropertyValuesHolder pvh = PropertyValuesHolder.ofMultiFloat(propertyName, converter,
evaluator, values);
return ObjectAnimator.ofPropertyValuesHolder(target, pvh);
}
/**
* 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

View File

@@ -169,6 +169,84 @@ public class PropertyValuesHolder implements Cloneable {
return new IntPropertyValuesHolder(property, values);
}
/**
* Constructs and returns a PropertyValuesHolder with a given property name and
* set of <code>int[]</code> values. At least two <code>int[]</code> values must be supplied,
* a start and end value. If more values are supplied, the values will be animated from the
* start, through all intermediate values to the end value. When used with ObjectAnimator,
* the elements of the array represent the parameters of the setter function.
*
* @param propertyName The name of the property being animated. Can also be the name of the
* entire setter method. Should not be null.
* @param values The values that the property will animate between.
* @return PropertyValuesHolder The constructed PropertyValuesHolder object.
* @see IntArrayEvaluator#IntArrayEvaluator(int[])
* @see ObjectAnimator#ofMultiInt(Object, String, TypeConverter, TypeEvaluator, Object[])
*/
public static PropertyValuesHolder ofMultiInt(String propertyName, int[][] values) {
if (values.length < 2) {
throw new IllegalArgumentException("At least 2 values must be supplied");
}
int numParameters = 0;
for (int i = 0; i < values.length; i++) {
if (values[i] == null) {
throw new IllegalArgumentException("values must not be null");
}
int length = values[i].length;
if (i == 0) {
numParameters = length;
} else if (length != numParameters) {
throw new IllegalArgumentException("Values must all have the same length");
}
}
IntArrayEvaluator evaluator = new IntArrayEvaluator(new int[numParameters]);
return new MultiIntValuesHolder(propertyName, null, evaluator, (Object[]) values);
}
/**
* Constructs and returns a PropertyValuesHolder with a given property and
* set of Object values for use with ObjectAnimator multi-value setters. The Object
* values are converted to <code>int[]</code> using the converter.
*
* @param propertyName The property being animated or complete name of the setter.
* Should not be null.
* @param converter Used to convert the animated value to setter parameters.
* @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 ObjectAnimator#ofMultiInt(Object, String, TypeConverter, TypeEvaluator, Object[])
* @see ObjectAnimator#ofPropertyValuesHolder(Object, PropertyValuesHolder...)
*/
public static <V> PropertyValuesHolder ofMultiInt(String propertyName,
TypeConverter<V, int[]> converter, TypeEvaluator<V> evaluator, V... values) {
return new MultiIntValuesHolder(propertyName, converter, evaluator, values);
}
/**
* Constructs and returns a PropertyValuesHolder object with the specified property name or
* setter name for use in a multi-int setter function using ObjectAnimator. The values can be
* of any type, but the type should be consistent so that the supplied
* {@link android.animation.TypeEvaluator} can be used to to evaluate the animated value. The
* <code>converter</code> converts the values to parameters in the setter function.
*
* <p>At least two values must be supplied, a start and an end value.</p>
*
* @param propertyName The name of the property to associate with the set of values. This
* may also be the complete name of a setter function.
* @param converter Converts <code>values</code> into int parameters for the setter.
* Can be null if the Keyframes have int[] values.
* @param evaluator Used to interpolate between values.
* @param values The values at specific fractional times to evaluate between
* @return A PropertyValuesHolder for a multi-int parameter setter.
*/
public static <T> PropertyValuesHolder ofMultiInt(String propertyName,
TypeConverter<T, int[]> converter, TypeEvaluator<T> evaluator, Keyframe... values) {
KeyframeSet keyframeSet = KeyframeSet.ofKeyframe(values);
return new MultiIntValuesHolder(propertyName, converter, evaluator, keyframeSet);
}
/**
* Constructs and returns a PropertyValuesHolder with a given property name and
* set of float values.
@@ -191,6 +269,83 @@ public class PropertyValuesHolder implements Cloneable {
return new FloatPropertyValuesHolder(property, values);
}
/**
* Constructs and returns a PropertyValuesHolder with a given property name and
* set of <code>float[]</code> values. At least two <code>float[]</code> values must be supplied,
* a start and end value. If more values are supplied, the values will be animated from the
* start, through all intermediate values to the end value. When used with ObjectAnimator,
* the elements of the array represent the parameters of the setter function.
*
* @param propertyName The name of the property being animated. Can also be the name of the
* entire setter method. Should not be null.
* @param values The values that the property will animate between.
* @return PropertyValuesHolder The constructed PropertyValuesHolder object.
* @see FloatArrayEvaluator#FloatArrayEvaluator(float[])
* @see ObjectAnimator#ofMultiFloat(Object, String, TypeConverter, TypeEvaluator, Object[])
*/
public static PropertyValuesHolder ofMultiFloat(String propertyName, float[][] values) {
if (values.length < 2) {
throw new IllegalArgumentException("At least 2 values must be supplied");
}
int numParameters = 0;
for (int i = 0; i < values.length; i++) {
if (values[i] == null) {
throw new IllegalArgumentException("values must not be null");
}
int length = values[i].length;
if (i == 0) {
numParameters = length;
} else if (length != numParameters) {
throw new IllegalArgumentException("Values must all have the same length");
}
}
FloatArrayEvaluator evaluator = new FloatArrayEvaluator(new float[numParameters]);
return new MultiFloatValuesHolder(propertyName, null, evaluator, (Object[]) values);
}
/**
* Constructs and returns a PropertyValuesHolder with a given property and
* set of Object values for use with ObjectAnimator multi-value setters. The Object
* values are converted to <code>float[]</code> using the converter.
*
* @param propertyName The property being animated or complete name of the setter.
* Should not be null.
* @param converter Used to convert the animated value to setter parameters.
* @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 ObjectAnimator#ofMultiFloat(Object, String, TypeConverter, TypeEvaluator, Object[])
*/
public static <V> PropertyValuesHolder ofMultiFloat(String propertyName,
TypeConverter<V, float[]> converter, TypeEvaluator<V> evaluator, V... values) {
return new MultiFloatValuesHolder(propertyName, converter, evaluator, values);
}
/**
* Constructs and returns a PropertyValuesHolder object with the specified property name or
* setter name for use in a multi-float setter function using ObjectAnimator. The values can be
* of any type, but the type should be consistent so that the supplied
* {@link android.animation.TypeEvaluator} can be used to to evaluate the animated value. The
* <code>converter</code> converts the values to parameters in the setter function.
*
* <p>At least two values must be supplied, a start and an end value.</p>
*
* @param propertyName The name of the property to associate with the set of values. This
* may also be the complete name of a setter function.
* @param converter Converts <code>values</code> into float parameters for the setter.
* Can be null if the Keyframes have float[] values.
* @param evaluator Used to interpolate between values.
* @param values The values at specific fractional times to evaluate between
* @return A PropertyValuesHolder for a multi-float parameter setter.
*/
public static <T> PropertyValuesHolder ofMultiFloat(String propertyName,
TypeConverter<T, float[]> converter, TypeEvaluator<T> evaluator, Keyframe... values) {
KeyframeSet keyframeSet = KeyframeSet.ofKeyframe(values);
return new MultiFloatValuesHolder(propertyName, converter, evaluator, keyframeSet);
}
/**
* Constructs and returns a PropertyValuesHolder with a given property name and
* set of Object values. This variant also takes a TypeEvaluator because the system
@@ -1078,8 +1233,227 @@ public class PropertyValuesHolder implements Cloneable {
}
static class MultiFloatValuesHolder extends PropertyValuesHolder {
private int mJniSetter;
private static final HashMap<Class, HashMap<String, Integer>> sJNISetterPropertyMap =
new HashMap<Class, HashMap<String, Integer>>();
public MultiFloatValuesHolder(String propertyName, TypeConverter converter,
TypeEvaluator evaluator, Object... values) {
super(propertyName);
setConverter(converter);
setObjectValues(values);
setEvaluator(evaluator);
}
public MultiFloatValuesHolder(String propertyName, TypeConverter converter,
TypeEvaluator evaluator, KeyframeSet keyframeSet) {
super(propertyName);
setConverter(converter);
mKeyframeSet = keyframeSet;
setEvaluator(evaluator);
}
/**
* 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 ObjectAnimator
* to handle turning the value calculated by ValueAnimator 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
*/
@Override
void setAnimatedValue(Object target) {
float[] values = (float[]) getAnimatedValue();
int numParameters = values.length;
if (mJniSetter != 0) {
switch (numParameters) {
case 1:
nCallFloatMethod(target, mJniSetter, values[0]);
break;
case 2:
nCallTwoFloatMethod(target, mJniSetter, values[0], values[1]);
break;
case 4:
nCallFourFloatMethod(target, mJniSetter, values[0], values[1],
values[2], values[3]);
break;
default: {
nCallMultipleFloatMethod(target, mJniSetter, values);
break;
}
}
}
}
/**
* Internal function (called from ObjectAnimator) to set up the setter and getter
* prior to running the animation. No getter can be used for multiple parameters.
*
* @param target The object on which the setter exists.
*/
@Override
void setupSetterAndGetter(Object target) {
setupSetter(target.getClass());
}
@Override
void setupSetter(Class targetClass) {
if (mJniSetter != 0) {
return;
}
try {
mPropertyMapLock.writeLock().lock();
HashMap<String, Integer> propertyMap = sJNISetterPropertyMap.get(targetClass);
if (propertyMap != null) {
Integer jniSetterInteger = propertyMap.get(mPropertyName);
if (jniSetterInteger != null) {
mJniSetter = jniSetterInteger;
}
}
if (mJniSetter == 0) {
String methodName = getMethodName("set", mPropertyName);
calculateValue(0f);
float[] values = (float[]) getAnimatedValue();
int numParams = values.length;
try {
mJniSetter = nGetMultipleFloatMethod(targetClass, methodName, numParams);
} catch (NoSuchMethodError e) {
// try without the 'set' prefix
mJniSetter = nGetMultipleFloatMethod(targetClass, mPropertyName, numParams);
}
if (mJniSetter != 0) {
if (propertyMap == null) {
propertyMap = new HashMap<String, Integer>();
sJNISetterPropertyMap.put(targetClass, propertyMap);
}
propertyMap.put(mPropertyName, mJniSetter);
}
}
} finally {
mPropertyMapLock.writeLock().unlock();
}
}
}
static class MultiIntValuesHolder extends PropertyValuesHolder {
private int mJniSetter;
private static final HashMap<Class, HashMap<String, Integer>> sJNISetterPropertyMap =
new HashMap<Class, HashMap<String, Integer>>();
public MultiIntValuesHolder(String propertyName, TypeConverter converter,
TypeEvaluator evaluator, Object... values) {
super(propertyName);
setConverter(converter);
setObjectValues(values);
setEvaluator(evaluator);
}
public MultiIntValuesHolder(String propertyName, TypeConverter converter,
TypeEvaluator evaluator, KeyframeSet keyframeSet) {
super(propertyName);
setConverter(converter);
mKeyframeSet = keyframeSet;
setEvaluator(evaluator);
}
/**
* 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 ObjectAnimator
* to handle turning the value calculated by ValueAnimator 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
*/
@Override
void setAnimatedValue(Object target) {
int[] values = (int[]) getAnimatedValue();
int numParameters = values.length;
if (mJniSetter != 0) {
switch (numParameters) {
case 1:
nCallIntMethod(target, mJniSetter, values[0]);
break;
case 2:
nCallTwoIntMethod(target, mJniSetter, values[0], values[1]);
break;
case 4:
nCallFourIntMethod(target, mJniSetter, values[0], values[1],
values[2], values[3]);
break;
default: {
nCallMultipleIntMethod(target, mJniSetter, values);
break;
}
}
}
}
/**
* Internal function (called from ObjectAnimator) to set up the setter and getter
* prior to running the animation. No getter can be used for multiple parameters.
*
* @param target The object on which the setter exists.
*/
@Override
void setupSetterAndGetter(Object target) {
setupSetter(target.getClass());
}
@Override
void setupSetter(Class targetClass) {
if (mJniSetter != 0) {
return;
}
try {
mPropertyMapLock.writeLock().lock();
HashMap<String, Integer> propertyMap = sJNISetterPropertyMap.get(targetClass);
if (propertyMap != null) {
Integer jniSetterInteger = propertyMap.get(mPropertyName);
if (jniSetterInteger != null) {
mJniSetter = jniSetterInteger;
}
}
if (mJniSetter == 0) {
String methodName = getMethodName("set", mPropertyName);
calculateValue(0f);
int[] values = (int[]) getAnimatedValue();
int numParams = values.length;
try {
mJniSetter = nGetMultipleIntMethod(targetClass, methodName, numParams);
} catch (NoSuchMethodError e) {
// try without the 'set' prefix
mJniSetter = nGetMultipleIntMethod(targetClass, mPropertyName, numParams);
}
if (mJniSetter != 0) {
if (propertyMap == null) {
propertyMap = new HashMap<String, Integer>();
sJNISetterPropertyMap.put(targetClass, propertyMap);
}
propertyMap.put(mPropertyName, mJniSetter);
}
}
} finally {
mPropertyMapLock.writeLock().unlock();
}
}
}
native static private int nGetIntMethod(Class targetClass, String methodName);
native static private int nGetFloatMethod(Class targetClass, String methodName);
native static private int nGetMultipleIntMethod(Class targetClass, String methodName,
int numParams);
native static private int nGetMultipleFloatMethod(Class targetClass, String methodName,
int numParams);
native static private void nCallIntMethod(Object target, int methodID, int arg);
native static private void nCallFloatMethod(Object target, int methodID, float arg);
native static private void nCallTwoIntMethod(Object target, int methodID, int arg1, int arg2);
native static private void nCallFourIntMethod(Object target, int methodID, int arg1, int arg2,
int arg3, int arg4);
native static private void nCallMultipleIntMethod(Object target, int methodID, int[] args);
native static private void nCallTwoFloatMethod(Object target, int methodID, float arg1,
float arg2);
native static private void nCallFourFloatMethod(Object target, int methodID, float arg1,
float arg2, float arg3, float arg4);
native static private void nCallMultipleFloatMethod(Object target, int methodID, float[] args);
}

View File

@@ -47,6 +47,32 @@ static jmethodID android_animation_PropertyValuesHolder_getFloatMethod(
return mid;
}
static jmethodID getMultiparameterMethod(JNIEnv* env, jclass targetClass, jstring methodName,
jint parameterCount, char parameterType)
{
const char *nativeString = env->GetStringUTFChars(methodName, 0);
char *signature = new char[parameterCount + 4];
signature[0] = '(';
memset(&(signature[1]), parameterType, parameterCount);
strcpy(&(signature[parameterCount + 1]), ")V");
jmethodID mid = env->GetMethodID(targetClass, nativeString, signature);
delete[] signature;
env->ReleaseStringUTFChars(methodName, nativeString);
return mid;
}
static jmethodID android_animation_PropertyValuesHolder_getMultipleFloatMethod(
JNIEnv* env, jclass pvhClass, jclass targetClass, jstring methodName, jint parameterCount)
{
return getMultiparameterMethod(env, targetClass, methodName, parameterCount, 'F');
}
static jmethodID android_animation_PropertyValuesHolder_getMultipleIntMethod(
JNIEnv* env, jclass pvhClass, jclass targetClass, jstring methodName, jint parameterCount)
{
return getMultiparameterMethod(env, targetClass, methodName, parameterCount, 'I');
}
static void android_animation_PropertyValuesHolder_callIntMethod(
JNIEnv* env, jclass pvhObject, jobject target, jmethodID methodID, int arg)
{
@@ -59,15 +85,85 @@ static void android_animation_PropertyValuesHolder_callFloatMethod(
env->CallVoidMethod(target, methodID, arg);
}
static void android_animation_PropertyValuesHolder_callTwoFloatMethod(
JNIEnv* env, jclass pvhObject, jobject target, jmethodID methodID, float arg1, float arg2)
{
env->CallVoidMethod(target, methodID, arg1, arg2);
}
static void android_animation_PropertyValuesHolder_callFourFloatMethod(
JNIEnv* env, jclass pvhObject, jobject target, jmethodID methodID, float arg1, float arg2,
float arg3, float arg4)
{
env->CallVoidMethod(target, methodID, arg1, arg2, arg3, arg4);
}
static void android_animation_PropertyValuesHolder_callMultipleFloatMethod(
JNIEnv* env, jclass pvhObject, jobject target, jmethodID methodID, jfloatArray arg)
{
jsize parameterCount = env->GetArrayLength(arg);
jfloat *floatValues = env->GetFloatArrayElements(arg, NULL);
jvalue* values = new jvalue[parameterCount];
for (int i = 0; i < parameterCount; i++) {
values[i].f = floatValues[i];
}
env->CallVoidMethodA(target, methodID, values);
delete[] values;
env->ReleaseFloatArrayElements(arg, floatValues, JNI_ABORT);
}
static void android_animation_PropertyValuesHolder_callTwoIntMethod(
JNIEnv* env, jclass pvhObject, jobject target, jmethodID methodID, int arg1, int arg2)
{
env->CallVoidMethod(target, methodID, arg1, arg2);
}
static void android_animation_PropertyValuesHolder_callFourIntMethod(
JNIEnv* env, jclass pvhObject, jobject target, jmethodID methodID, int arg1, int arg2,
int arg3, int arg4)
{
env->CallVoidMethod(target, methodID, arg1, arg2, arg3, arg4);
}
static void android_animation_PropertyValuesHolder_callMultipleIntMethod(
JNIEnv* env, jclass pvhObject, jobject target, jmethodID methodID, jintArray arg)
{
jsize parameterCount = env->GetArrayLength(arg);
jint *intValues = env->GetIntArrayElements(arg, NULL);
jvalue* values = new jvalue[parameterCount];
for (int i = 0; i < parameterCount; i++) {
values[i].i = intValues[i];
}
env->CallVoidMethodA(target, methodID, values);
delete[] values;
env->ReleaseIntArrayElements(arg, intValues, JNI_ABORT);
}
static JNINativeMethod gMethods[] = {
{ "nGetIntMethod", "(Ljava/lang/Class;Ljava/lang/String;)I",
(void*)android_animation_PropertyValuesHolder_getIntMethod },
{ "nGetFloatMethod", "(Ljava/lang/Class;Ljava/lang/String;)I",
(void*)android_animation_PropertyValuesHolder_getFloatMethod },
{ "nGetMultipleFloatMethod", "(Ljava/lang/Class;Ljava/lang/String;I)I",
(void*)android_animation_PropertyValuesHolder_getMultipleFloatMethod },
{ "nGetMultipleIntMethod", "(Ljava/lang/Class;Ljava/lang/String;I)I",
(void*)android_animation_PropertyValuesHolder_getMultipleIntMethod },
{ "nCallIntMethod", "(Ljava/lang/Object;II)V",
(void*)android_animation_PropertyValuesHolder_callIntMethod },
{ "nCallFloatMethod", "(Ljava/lang/Object;IF)V",
(void*)android_animation_PropertyValuesHolder_callFloatMethod }
(void*)android_animation_PropertyValuesHolder_callFloatMethod },
{ "nCallTwoFloatMethod", "(Ljava/lang/Object;IFF)V",
(void*)android_animation_PropertyValuesHolder_callTwoFloatMethod },
{ "nCallFourFloatMethod", "(Ljava/lang/Object;IFFFF)V",
(void*)android_animation_PropertyValuesHolder_callFourFloatMethod },
{ "nCallMultipleFloatMethod", "(Ljava/lang/Object;I[F)V",
(void*)android_animation_PropertyValuesHolder_callMultipleFloatMethod },
{ "nCallTwoIntMethod", "(Ljava/lang/Object;III)V",
(void*)android_animation_PropertyValuesHolder_callTwoIntMethod },
{ "nCallFourIntMethod", "(Ljava/lang/Object;IIIII)V",
(void*)android_animation_PropertyValuesHolder_callFourIntMethod },
{ "nCallMultipleIntMethod", "(Ljava/lang/Object;I[I)V",
(void*)android_animation_PropertyValuesHolder_callMultipleIntMethod },
};
int register_android_animation_PropertyValuesHolder(JNIEnv* env)