diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java index 224823ee2ff11..1dee925f2bdd4 100644 --- a/core/java/android/animation/PropertyValuesHolder.java +++ b/core/java/android/animation/PropertyValuesHolder.java @@ -1177,6 +1177,15 @@ public class PropertyValuesHolder implements Cloneable { } } + @Override + public void setProperty(Property property) { + if (property instanceof IntProperty) { + mIntProperty = (IntProperty) property; + } else { + super.setProperty(property); + } + } + @Override public void setIntValues(int... values) { super.setIntValues(values); @@ -1315,6 +1324,15 @@ public class PropertyValuesHolder implements Cloneable { } } + @Override + public void setProperty(Property property) { + if (property instanceof FloatProperty) { + mFloatProperty = (FloatProperty) property; + } else { + super.setProperty(property); + } + } + @Override public void setFloatValues(float... values) { super.setFloatValues(values); @@ -1516,7 +1534,7 @@ public class PropertyValuesHolder implements Cloneable { } propertyMap.put(mPropertyName, mJniSetter); } - } + } } } diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java index 6762bea1ca350..7fa3947d80f95 100644 --- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java @@ -46,6 +46,7 @@ import android.util.IntArray; import android.util.Log; import android.util.LongArray; import android.util.PathParser; +import android.util.Property; import android.util.TimeUtils; import android.view.Choreographer; import android.view.DisplayListCanvas; @@ -390,9 +391,11 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { R.styleable.AnimatedVectorDrawableTarget_animation, 0); if (animResId != 0) { if (theme != null) { - final Animator objectAnimator = AnimatorInflater.loadAnimator( + // The animator here could be ObjectAnimator or AnimatorSet. + final Animator animator = AnimatorInflater.loadAnimator( res, theme, animResId, pathErrorScale); - state.addTargetAnimator(target, objectAnimator); + updateAnimatorProperty(animator, target, state.mVectorDrawable); + state.addTargetAnimator(target, animator); } else { // The animation may be theme-dependent. As a // workaround until Animator has full support for @@ -414,6 +417,36 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { mRes = state.mPendingAnims == null ? null : res; } + private static void updateAnimatorProperty(Animator animator, String targetName, + VectorDrawable vectorDrawable) { + if (animator instanceof ObjectAnimator) { + // Change the property of the Animator from using reflection based on the property + // name to a Property object that wraps the setter and getter for modifying that + // specific property for a given object. By replacing the reflection with a direct call, + // we can largely reduce the time it takes for a animator to modify a VD property. + PropertyValuesHolder[] holders = ((ObjectAnimator) animator).getValues(); + for (int i = 0; i < holders.length; i++) { + PropertyValuesHolder pvh = holders[i]; + String propertyName = pvh.getPropertyName(); + Object targetNameObj = vectorDrawable.getTargetByName(targetName); + Property property = null; + if (targetNameObj instanceof VectorDrawable.VObject) { + property = ((VectorDrawable.VObject) targetNameObj).getProperty(propertyName); + } else if (targetNameObj instanceof VectorDrawable.VectorDrawableState) { + property = ((VectorDrawable.VectorDrawableState) targetNameObj) + .getProperty(propertyName); + } + if (property != null) { + pvh.setProperty(property); + } + } + } else if (animator instanceof AnimatorSet) { + for (Animator anim : ((AnimatorSet) animator).getChildAnimations()) { + updateAnimatorProperty(anim, targetName, vectorDrawable); + } + } + } + /** * Force to animate on UI thread. * @hide @@ -616,8 +649,9 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { for (int i = 0, count = pendingAnims.size(); i < count; i++) { final PendingAnimator pendingAnimator = pendingAnims.get(i); - final Animator objectAnimator = pendingAnimator.newInstance(res, t); - addTargetAnimator(pendingAnimator.target, objectAnimator); + final Animator animator = pendingAnimator.newInstance(res, t); + updateAnimatorProperty(animator, pendingAnimator.target, mVectorDrawable); + addTargetAnimator(pendingAnimator.target, animator); } } } diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index f5592fa7e4079..237c931771149 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -34,9 +34,12 @@ import android.graphics.Shader; import android.util.ArrayMap; import android.util.AttributeSet; import android.util.DisplayMetrics; +import android.util.FloatProperty; +import android.util.IntProperty; import android.util.LayoutDirection; import android.util.Log; import android.util.PathParser; +import android.util.Property; import android.util.Xml; import com.android.internal.R; @@ -790,6 +793,26 @@ public class VectorDrawable extends Drawable { int mLastSWCachePixelCount = 0; int mLastHWCachePixelCount = 0; + final static Property ALPHA = + new FloatProperty("alpha") { + @Override + public void setValue(VectorDrawableState state, float value) { + state.setAlpha(value); + } + + @Override + public Float get(VectorDrawableState state) { + return state.getAlpha(); + } + }; + + Property getProperty(String propertyName) { + if (ALPHA.getName().equals(propertyName)) { + return ALPHA; + } + return null; + } + // This tracks the total native allocation for all the nodes. private int mAllocationOfAllNodes = 0; @@ -967,7 +990,7 @@ public class VectorDrawable extends Drawable { } static class VGroup extends VObject { - private static final int ROTATE_INDEX = 0; + private static final int ROTATION_INDEX = 0; private static final int PIVOT_X_INDEX = 1; private static final int PIVOT_Y_INDEX = 2; private static final int SCALE_X_INDEX = 3; @@ -978,7 +1001,7 @@ public class VectorDrawable extends Drawable { private static final int NATIVE_ALLOCATION_SIZE = 100; - private static final HashMap sPropertyMap = + private static final HashMap sPropertyIndexMap = new HashMap() { { put("translateX", TRANSLATE_X_INDEX); @@ -987,19 +1010,123 @@ public class VectorDrawable extends Drawable { put("scaleY", SCALE_Y_INDEX); put("pivotX", PIVOT_X_INDEX); put("pivotY", PIVOT_Y_INDEX); - put("rotation", ROTATE_INDEX); + put("rotation", ROTATION_INDEX); } }; static int getPropertyIndex(String propertyName) { - if (sPropertyMap.containsKey(propertyName)) { - return sPropertyMap.get(propertyName); + if (sPropertyIndexMap.containsKey(propertyName)) { + return sPropertyIndexMap.get(propertyName); } else { // property not found return -1; } } + // Below are the Properties that wrap the setters to avoid reflection overhead in animations + private static final Property TRANSLATE_X = + new FloatProperty ("translateX") { + @Override + public void setValue(VGroup object, float value) { + object.setTranslateX(value); + } + + @Override + public Float get(VGroup object) { + return object.getTranslateX(); + } + }; + + private static final Property TRANSLATE_Y = + new FloatProperty ("translateY") { + @Override + public void setValue(VGroup object, float value) { + object.setTranslateY(value); + } + + @Override + public Float get(VGroup object) { + return object.getTranslateY(); + } + }; + + private static final Property SCALE_X = + new FloatProperty ("scaleX") { + @Override + public void setValue(VGroup object, float value) { + object.setScaleX(value); + } + + @Override + public Float get(VGroup object) { + return object.getScaleX(); + } + }; + + private static final Property SCALE_Y = + new FloatProperty ("scaleY") { + @Override + public void setValue(VGroup object, float value) { + object.setScaleY(value); + } + + @Override + public Float get(VGroup object) { + return object.getScaleY(); + } + }; + + private static final Property PIVOT_X = + new FloatProperty ("pivotX") { + @Override + public void setValue(VGroup object, float value) { + object.setPivotX(value); + } + + @Override + public Float get(VGroup object) { + return object.getPivotX(); + } + }; + + private static final Property PIVOT_Y = + new FloatProperty ("pivotY") { + @Override + public void setValue(VGroup object, float value) { + object.setPivotY(value); + } + + @Override + public Float get(VGroup object) { + return object.getPivotY(); + } + }; + + private static final Property ROTATION = + new FloatProperty ("rotation") { + @Override + public void setValue(VGroup object, float value) { + object.setRotation(value); + } + + @Override + public Float get(VGroup object) { + return object.getRotation(); + } + }; + + private static final HashMap sPropertyMap = + new HashMap() { + { + put("translateX", TRANSLATE_X); + put("translateY", TRANSLATE_Y); + put("scaleX", SCALE_X); + put("scaleY", SCALE_Y); + put("pivotX", PIVOT_X); + put("pivotY", PIVOT_Y); + put("rotation", ROTATION); + } + }; // Temp array to store transform values obtained from native. private float[] mTransform; ///////////////////////////////////////////////////// @@ -1055,6 +1182,15 @@ public class VectorDrawable extends Drawable { mNativePtr = nCreateGroup(); } + Property getProperty(String propertyName) { + if (sPropertyMap.containsKey(propertyName)) { + return sPropertyMap.get(propertyName); + } else { + // property not found + return null; + } + } + public String getGroupName() { return mGroupName; } @@ -1102,7 +1238,7 @@ public class VectorDrawable extends Drawable { throw new RuntimeException("Error: inconsistent property count"); } float rotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, - mTransform[ROTATE_INDEX]); + mTransform[ROTATION_INDEX]); float pivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mTransform[PIVOT_X_INDEX]); float pivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, @@ -1288,6 +1424,27 @@ public class VectorDrawable extends Drawable { String mPathName; @Config int mChangingConfigurations; + private static final Property PATH_DATA = + new Property(PathParser.PathData.class, "pathData") { + @Override + public void set(VPath object, PathParser.PathData data) { + object.setPathData(data); + } + + @Override + public PathParser.PathData get(VPath object) { + return object.getPathData(); + } + }; + + Property getProperty(String propertyName) { + if (PATH_DATA.getName().equals(propertyName)) { + return PATH_DATA; + } + // property not found + return null; + } + public VPath() { // Empty constructor. } @@ -1410,7 +1567,7 @@ public class VectorDrawable extends Drawable { private static final int NATIVE_ALLOCATION_SIZE = 264; // Property map for animatable attributes. - private final static HashMap sPropertyMap + private final static HashMap sPropertyIndexMap = new HashMap () { { put("strokeWidth", STROKE_WIDTH_INDEX); @@ -1424,6 +1581,125 @@ public class VectorDrawable extends Drawable { } }; + // Below are the Properties that wrap the setters to avoid reflection overhead in animations + private static final Property STROKE_WIDTH = + new FloatProperty ("strokeWidth") { + @Override + public void setValue(VFullPath object, float value) { + object.setStrokeWidth(value); + } + + @Override + public Float get(VFullPath object) { + return object.getStrokeWidth(); + } + }; + + private static final Property STROKE_COLOR = + new IntProperty ("strokeColor") { + @Override + public void setValue(VFullPath object, int value) { + object.setStrokeColor(value); + } + + @Override + public Integer get(VFullPath object) { + return object.getStrokeColor(); + } + }; + + private static final Property STROKE_ALPHA = + new FloatProperty ("strokeAlpha") { + @Override + public void setValue(VFullPath object, float value) { + object.setStrokeAlpha(value); + } + + @Override + public Float get(VFullPath object) { + return object.getStrokeAlpha(); + } + }; + + private static final Property FILL_COLOR = + new IntProperty("fillColor") { + @Override + public void setValue(VFullPath object, int value) { + object.setFillColor(value); + } + + @Override + public Integer get(VFullPath object) { + return object.getFillColor(); + } + }; + + private static final Property FILL_ALPHA = + new FloatProperty ("fillAlpha") { + @Override + public void setValue(VFullPath object, float value) { + object.setFillAlpha(value); + } + + @Override + public Float get(VFullPath object) { + return object.getFillAlpha(); + } + }; + + private static final Property TRIM_PATH_START = + new FloatProperty ("trimPathStart") { + @Override + public void setValue(VFullPath object, float value) { + object.setTrimPathStart(value); + } + + @Override + public Float get(VFullPath object) { + return object.getTrimPathStart(); + } + }; + + private static final Property TRIM_PATH_END = + new FloatProperty ("trimPathEnd") { + @Override + public void setValue(VFullPath object, float value) { + object.setTrimPathEnd(value); + } + + @Override + public Float get(VFullPath object) { + return object.getTrimPathEnd(); + } + }; + + private static final Property TRIM_PATH_OFFSET = + new FloatProperty ("trimPathOffset") { + @Override + public void setValue(VFullPath object, float value) { + object.setTrimPathOffset(value); + } + + @Override + public Float get(VFullPath object) { + return object.getTrimPathOffset(); + } + }; + + private final static HashMap sPropertyMap + = new HashMap () { + { + put("strokeWidth", STROKE_WIDTH); + put("strokeColor", STROKE_COLOR); + put("strokeAlpha", STROKE_ALPHA); + put("fillColor", FILL_COLOR); + put("fillAlpha", FILL_ALPHA); + put("trimPathStart", TRIM_PATH_START); + put("trimPathEnd", TRIM_PATH_END); + put("trimPathOffset", TRIM_PATH_OFFSET); + } + }; + // Temp array to store property data obtained from native getter. private byte[] mPropertyData; ///////////////////////////////////////////////////// @@ -1446,11 +1722,24 @@ public class VectorDrawable extends Drawable { mFillColors = copy.mFillColors; } + Property getProperty(String propertyName) { + Property p = super.getProperty(propertyName); + if (p != null) { + return p; + } + if (sPropertyMap.containsKey(propertyName)) { + return sPropertyMap.get(propertyName); + } else { + // property not found + return null; + } + } + int getPropertyIndex(String propertyName) { - if (!sPropertyMap.containsKey(propertyName)) { + if (!sPropertyIndexMap.containsKey(propertyName)) { return -1; } else { - return sPropertyMap.get(propertyName); + return sPropertyIndexMap.get(propertyName); } } @@ -1784,6 +2073,7 @@ public class VectorDrawable extends Drawable { abstract boolean onStateChange(int[] state); abstract boolean isStateful(); abstract int getNativeSize(); + abstract Property getProperty(String propertyName); } private static native long nCreateTree(long rootGroupPtr);