Merge "Improve the property modification effiency of VectorDrawable animators" into nyc-mr1-dev

This commit is contained in:
Doris Liu
2016-06-09 21:30:01 +00:00
committed by Android (Google) Code Review
3 changed files with 356 additions and 14 deletions

View File

@@ -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);
}
}
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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<VectorDrawableState, Float> ALPHA =
new FloatProperty<VectorDrawableState>("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<String, Integer> sPropertyMap =
private static final HashMap<String, Integer> sPropertyIndexMap =
new HashMap<String, Integer>() {
{
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<VGroup, Float> TRANSLATE_X =
new FloatProperty<VGroup> ("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<VGroup, Float> TRANSLATE_Y =
new FloatProperty<VGroup> ("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<VGroup, Float> SCALE_X =
new FloatProperty<VGroup> ("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<VGroup, Float> SCALE_Y =
new FloatProperty<VGroup> ("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<VGroup, Float> PIVOT_X =
new FloatProperty<VGroup> ("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<VGroup, Float> PIVOT_Y =
new FloatProperty<VGroup> ("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<VGroup, Float> ROTATION =
new FloatProperty<VGroup> ("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<String, Property> sPropertyMap =
new HashMap<String, Property>() {
{
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<VPath, PathParser.PathData> PATH_DATA =
new Property<VPath, PathParser.PathData>(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<String, Integer> sPropertyMap
private final static HashMap<String, Integer> sPropertyIndexMap
= new HashMap<String, Integer> () {
{
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<VFullPath, Float> STROKE_WIDTH =
new FloatProperty<VFullPath> ("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<VFullPath, Integer> STROKE_COLOR =
new IntProperty<VFullPath> ("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<VFullPath, Float> STROKE_ALPHA =
new FloatProperty<VFullPath> ("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<VFullPath, Integer> FILL_COLOR =
new IntProperty<VFullPath>("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<VFullPath, Float> FILL_ALPHA =
new FloatProperty<VFullPath> ("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<VFullPath, Float> TRIM_PATH_START =
new FloatProperty<VFullPath> ("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<VFullPath, Float> TRIM_PATH_END =
new FloatProperty<VFullPath> ("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<VFullPath, Float> TRIM_PATH_OFFSET =
new FloatProperty<VFullPath> ("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<String, Property> sPropertyMap
= new HashMap<String, Property> () {
{
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);