Loading core/java/android/animation/AnimatorInflater.java +33 −19 Original line number Diff line number Diff line Loading @@ -92,11 +92,17 @@ public class AnimatorInflater { */ public static Animator loadAnimator(Resources resources, Theme theme, int id) throws NotFoundException { return loadAnimator(resources, theme, id, 1); } /** @hide */ public static Animator loadAnimator(Resources resources, Theme theme, int id, float pathErrorScale) throws NotFoundException { XmlResourceParser parser = null; try { parser = resources.getAnimation(id); return createAnimatorFromXml(resources, theme, parser); return createAnimatorFromXml(resources, theme, parser, pathErrorScale); } catch (XmlPullParserException ex) { Resources.NotFoundException rnf = new Resources.NotFoundException("Can't load animation resource ID #0x" + Loading Loading @@ -177,7 +183,7 @@ public class AnimatorInflater { } if (animator == null) { animator = createAnimatorFromXml(context.getResources(), context.getTheme(), parser); context.getTheme(), parser, 1f); } if (animator == null) { Loading Loading @@ -248,9 +254,11 @@ public class AnimatorInflater { * @param arrayAnimator Incoming typed array for Animator's attributes. * @param arrayObjectAnimator Incoming typed array for Object Animator's * attributes. * @param pixelSize The relative pixel size, used to calculate the * maximum error for path animations. */ private static void parseAnimatorFromTypeArray(ValueAnimator anim, TypedArray arrayAnimator, TypedArray arrayObjectAnimator) { TypedArray arrayAnimator, TypedArray arrayObjectAnimator, float pixelSize) { long duration = arrayAnimator.getInt(R.styleable.Animator_duration, 300); long startDelay = arrayAnimator.getInt(R.styleable.Animator_startOffset, 0); Loading Loading @@ -303,7 +311,7 @@ public class AnimatorInflater { } if (arrayObjectAnimator != null) { setupObjectAnimator(anim, arrayObjectAnimator, getFloats); setupObjectAnimator(anim, arrayObjectAnimator, getFloats, pixelSize); } } Loading Loading @@ -351,9 +359,11 @@ public class AnimatorInflater { * @param anim The target Animator which will be updated. * @param arrayObjectAnimator TypedArray for the ObjectAnimator. * @param getFloats True if the value type is float. * @param pixelSize The relative pixel size, used to calculate the * maximum error for path animations. */ private static void setupObjectAnimator(ValueAnimator anim, TypedArray arrayObjectAnimator, boolean getFloats) { boolean getFloats, float pixelSize) { ObjectAnimator oa = (ObjectAnimator) anim; String pathData = arrayObjectAnimator.getString(R.styleable.PropertyAnimator_pathData); Loading @@ -370,7 +380,8 @@ public class AnimatorInflater { + " propertyXName or propertyYName is needed for PathData"); } else { Path path = PathParser.createPathFromPathData(pathData); PathKeyframes keyframeSet = KeyframeSet.ofPath(path); float error = 0.5f * pixelSize; // max half a pixel error PathKeyframes keyframeSet = KeyframeSet.ofPath(path, error); Keyframes xKeyframes; Keyframes yKeyframes; if (getFloats) { Loading Loading @@ -487,13 +498,15 @@ public class AnimatorInflater { } } private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser) private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser, float pixelSize) throws XmlPullParserException, IOException { return createAnimatorFromXml(res, theme, parser, Xml.asAttributeSet(parser), null, 0); return createAnimatorFromXml(res, theme, parser, Xml.asAttributeSet(parser), null, 0, pixelSize); } private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser, AttributeSet attrs, AnimatorSet parent, int sequenceOrdering) AttributeSet attrs, AnimatorSet parent, int sequenceOrdering, float pixelSize) throws XmlPullParserException, IOException { Animator anim = null; Loading @@ -513,9 +526,9 @@ public class AnimatorInflater { String name = parser.getName(); if (name.equals("objectAnimator")) { anim = loadObjectAnimator(res, theme, attrs); anim = loadObjectAnimator(res, theme, attrs, pixelSize); } else if (name.equals("animator")) { anim = loadAnimator(res, theme, attrs, null); anim = loadAnimator(res, theme, attrs, null, pixelSize); } else if (name.equals("set")) { anim = new AnimatorSet(); TypedArray a; Loading @@ -526,7 +539,8 @@ public class AnimatorInflater { } int ordering = a.getInt(R.styleable.AnimatorSet_ordering, TOGETHER); createAnimatorFromXml(res, theme, parser, attrs, (AnimatorSet) anim, ordering); createAnimatorFromXml(res, theme, parser, attrs, (AnimatorSet) anim, ordering, pixelSize); a.recycle(); } else { throw new RuntimeException("Unknown animator name: " + parser.getName()); Loading Loading @@ -556,11 +570,11 @@ public class AnimatorInflater { } private static ObjectAnimator loadObjectAnimator(Resources res, Theme theme, AttributeSet attrs) throws NotFoundException { private static ObjectAnimator loadObjectAnimator(Resources res, Theme theme, AttributeSet attrs, float pathErrorScale) throws NotFoundException { ObjectAnimator anim = new ObjectAnimator(); loadAnimator(res, theme, attrs, anim); loadAnimator(res, theme, attrs, anim, pathErrorScale); return anim; } Loading @@ -575,7 +589,7 @@ public class AnimatorInflater { * ObjectAnimator */ private static ValueAnimator loadAnimator(Resources res, Theme theme, AttributeSet attrs, ValueAnimator anim) AttributeSet attrs, ValueAnimator anim, float pathErrorScale) throws NotFoundException { TypedArray arrayAnimator = null; Loading @@ -601,7 +615,7 @@ public class AnimatorInflater { anim = new ValueAnimator(); } parseAnimatorFromTypeArray(anim, arrayAnimator, arrayObjectAnimator); parseAnimatorFromTypeArray(anim, arrayAnimator, arrayObjectAnimator, pathErrorScale); final int resID = arrayAnimator.getResourceId(R.styleable.Animator_interpolator, 0); Loading core/java/android/animation/KeyframeSet.java +4 −0 Original line number Diff line number Diff line Loading @@ -154,6 +154,10 @@ class KeyframeSet implements Keyframes { return new PathKeyframes(path); } public static PathKeyframes ofPath(Path path, float error) { return new PathKeyframes(path, error); } /** * Sets the TypeEvaluator to be used when calculating animated values. This object * is required only for KeyframeSets that are not either IntKeyframeSet or FloatKeyframeSet, Loading graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java +7 −3 Original line number Diff line number Diff line Loading @@ -252,6 +252,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable { throws XmlPullParserException, IOException { int eventType = parser.getEventType(); float pathErrorScale = 1; while (eventType != XmlPullParser.END_DOCUMENT) { if (eventType == XmlPullParser.START_TAG) { final String tagName = parser.getName(); Loading @@ -261,9 +262,11 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable { int drawableRes = a.getResourceId( R.styleable.AnimatedVectorDrawable_drawable, 0); if (drawableRes != 0) { mAnimatedVectorState.mVectorDrawable = (VectorDrawable) res.getDrawable( VectorDrawable vectorDrawable = (VectorDrawable) res.getDrawable( drawableRes, theme).mutate(); mAnimatedVectorState.mVectorDrawable.setAllowCaching(false); vectorDrawable.setAllowCaching(false); pathErrorScale = vectorDrawable.getPixelSize(); mAnimatedVectorState.mVectorDrawable = vectorDrawable; } a.recycle(); } else if (TARGET.equals(tagName)) { Loading @@ -275,7 +278,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable { int id = a.getResourceId( R.styleable.AnimatedVectorDrawableTarget_animation, 0); if (id != 0) { Animator objectAnimator = AnimatorInflater.loadAnimator(res, theme, id); Animator objectAnimator = AnimatorInflater.loadAnimator(res, theme, id, pathErrorScale); setupAnimatorsForTarget(target, objectAnimator); } a.recycle(); Loading graphics/java/android/graphics/drawable/VectorDrawable.java +23 −0 Original line number Diff line number Diff line Loading @@ -368,6 +368,29 @@ public class VectorDrawable extends Drawable { } } /** * The size of a pixel when scaled from the intrinsic dimension to the viewport dimension. * This is used to calculate the path animation accuracy. * * @hide */ public float getPixelSize() { if (mVectorState == null && mVectorState.mVPathRenderer == null || mVectorState.mVPathRenderer.mBaseWidth == 0 || mVectorState.mVPathRenderer.mBaseHeight == 0 || mVectorState.mVPathRenderer.mViewportHeight == 0 || mVectorState.mVPathRenderer.mViewportWidth == 0) { return 1; // fall back to 1:1 pixel mapping. } float intrinsicWidth = mVectorState.mVPathRenderer.mBaseWidth; float intrinsicHeight = mVectorState.mVPathRenderer.mBaseHeight; float viewportWidth = mVectorState.mVPathRenderer.mViewportWidth; float viewportHeight = mVectorState.mVPathRenderer.mViewportHeight; float scaleX = viewportWidth / intrinsicWidth; float scaleY = viewportHeight / intrinsicHeight; return Math.min(scaleX, scaleY); } /** @hide */ public static VectorDrawable create(Resources resources, int rid) { try { Loading Loading
core/java/android/animation/AnimatorInflater.java +33 −19 Original line number Diff line number Diff line Loading @@ -92,11 +92,17 @@ public class AnimatorInflater { */ public static Animator loadAnimator(Resources resources, Theme theme, int id) throws NotFoundException { return loadAnimator(resources, theme, id, 1); } /** @hide */ public static Animator loadAnimator(Resources resources, Theme theme, int id, float pathErrorScale) throws NotFoundException { XmlResourceParser parser = null; try { parser = resources.getAnimation(id); return createAnimatorFromXml(resources, theme, parser); return createAnimatorFromXml(resources, theme, parser, pathErrorScale); } catch (XmlPullParserException ex) { Resources.NotFoundException rnf = new Resources.NotFoundException("Can't load animation resource ID #0x" + Loading Loading @@ -177,7 +183,7 @@ public class AnimatorInflater { } if (animator == null) { animator = createAnimatorFromXml(context.getResources(), context.getTheme(), parser); context.getTheme(), parser, 1f); } if (animator == null) { Loading Loading @@ -248,9 +254,11 @@ public class AnimatorInflater { * @param arrayAnimator Incoming typed array for Animator's attributes. * @param arrayObjectAnimator Incoming typed array for Object Animator's * attributes. * @param pixelSize The relative pixel size, used to calculate the * maximum error for path animations. */ private static void parseAnimatorFromTypeArray(ValueAnimator anim, TypedArray arrayAnimator, TypedArray arrayObjectAnimator) { TypedArray arrayAnimator, TypedArray arrayObjectAnimator, float pixelSize) { long duration = arrayAnimator.getInt(R.styleable.Animator_duration, 300); long startDelay = arrayAnimator.getInt(R.styleable.Animator_startOffset, 0); Loading Loading @@ -303,7 +311,7 @@ public class AnimatorInflater { } if (arrayObjectAnimator != null) { setupObjectAnimator(anim, arrayObjectAnimator, getFloats); setupObjectAnimator(anim, arrayObjectAnimator, getFloats, pixelSize); } } Loading Loading @@ -351,9 +359,11 @@ public class AnimatorInflater { * @param anim The target Animator which will be updated. * @param arrayObjectAnimator TypedArray for the ObjectAnimator. * @param getFloats True if the value type is float. * @param pixelSize The relative pixel size, used to calculate the * maximum error for path animations. */ private static void setupObjectAnimator(ValueAnimator anim, TypedArray arrayObjectAnimator, boolean getFloats) { boolean getFloats, float pixelSize) { ObjectAnimator oa = (ObjectAnimator) anim; String pathData = arrayObjectAnimator.getString(R.styleable.PropertyAnimator_pathData); Loading @@ -370,7 +380,8 @@ public class AnimatorInflater { + " propertyXName or propertyYName is needed for PathData"); } else { Path path = PathParser.createPathFromPathData(pathData); PathKeyframes keyframeSet = KeyframeSet.ofPath(path); float error = 0.5f * pixelSize; // max half a pixel error PathKeyframes keyframeSet = KeyframeSet.ofPath(path, error); Keyframes xKeyframes; Keyframes yKeyframes; if (getFloats) { Loading Loading @@ -487,13 +498,15 @@ public class AnimatorInflater { } } private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser) private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser, float pixelSize) throws XmlPullParserException, IOException { return createAnimatorFromXml(res, theme, parser, Xml.asAttributeSet(parser), null, 0); return createAnimatorFromXml(res, theme, parser, Xml.asAttributeSet(parser), null, 0, pixelSize); } private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser, AttributeSet attrs, AnimatorSet parent, int sequenceOrdering) AttributeSet attrs, AnimatorSet parent, int sequenceOrdering, float pixelSize) throws XmlPullParserException, IOException { Animator anim = null; Loading @@ -513,9 +526,9 @@ public class AnimatorInflater { String name = parser.getName(); if (name.equals("objectAnimator")) { anim = loadObjectAnimator(res, theme, attrs); anim = loadObjectAnimator(res, theme, attrs, pixelSize); } else if (name.equals("animator")) { anim = loadAnimator(res, theme, attrs, null); anim = loadAnimator(res, theme, attrs, null, pixelSize); } else if (name.equals("set")) { anim = new AnimatorSet(); TypedArray a; Loading @@ -526,7 +539,8 @@ public class AnimatorInflater { } int ordering = a.getInt(R.styleable.AnimatorSet_ordering, TOGETHER); createAnimatorFromXml(res, theme, parser, attrs, (AnimatorSet) anim, ordering); createAnimatorFromXml(res, theme, parser, attrs, (AnimatorSet) anim, ordering, pixelSize); a.recycle(); } else { throw new RuntimeException("Unknown animator name: " + parser.getName()); Loading Loading @@ -556,11 +570,11 @@ public class AnimatorInflater { } private static ObjectAnimator loadObjectAnimator(Resources res, Theme theme, AttributeSet attrs) throws NotFoundException { private static ObjectAnimator loadObjectAnimator(Resources res, Theme theme, AttributeSet attrs, float pathErrorScale) throws NotFoundException { ObjectAnimator anim = new ObjectAnimator(); loadAnimator(res, theme, attrs, anim); loadAnimator(res, theme, attrs, anim, pathErrorScale); return anim; } Loading @@ -575,7 +589,7 @@ public class AnimatorInflater { * ObjectAnimator */ private static ValueAnimator loadAnimator(Resources res, Theme theme, AttributeSet attrs, ValueAnimator anim) AttributeSet attrs, ValueAnimator anim, float pathErrorScale) throws NotFoundException { TypedArray arrayAnimator = null; Loading @@ -601,7 +615,7 @@ public class AnimatorInflater { anim = new ValueAnimator(); } parseAnimatorFromTypeArray(anim, arrayAnimator, arrayObjectAnimator); parseAnimatorFromTypeArray(anim, arrayAnimator, arrayObjectAnimator, pathErrorScale); final int resID = arrayAnimator.getResourceId(R.styleable.Animator_interpolator, 0); Loading
core/java/android/animation/KeyframeSet.java +4 −0 Original line number Diff line number Diff line Loading @@ -154,6 +154,10 @@ class KeyframeSet implements Keyframes { return new PathKeyframes(path); } public static PathKeyframes ofPath(Path path, float error) { return new PathKeyframes(path, error); } /** * Sets the TypeEvaluator to be used when calculating animated values. This object * is required only for KeyframeSets that are not either IntKeyframeSet or FloatKeyframeSet, Loading
graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java +7 −3 Original line number Diff line number Diff line Loading @@ -252,6 +252,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable { throws XmlPullParserException, IOException { int eventType = parser.getEventType(); float pathErrorScale = 1; while (eventType != XmlPullParser.END_DOCUMENT) { if (eventType == XmlPullParser.START_TAG) { final String tagName = parser.getName(); Loading @@ -261,9 +262,11 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable { int drawableRes = a.getResourceId( R.styleable.AnimatedVectorDrawable_drawable, 0); if (drawableRes != 0) { mAnimatedVectorState.mVectorDrawable = (VectorDrawable) res.getDrawable( VectorDrawable vectorDrawable = (VectorDrawable) res.getDrawable( drawableRes, theme).mutate(); mAnimatedVectorState.mVectorDrawable.setAllowCaching(false); vectorDrawable.setAllowCaching(false); pathErrorScale = vectorDrawable.getPixelSize(); mAnimatedVectorState.mVectorDrawable = vectorDrawable; } a.recycle(); } else if (TARGET.equals(tagName)) { Loading @@ -275,7 +278,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable { int id = a.getResourceId( R.styleable.AnimatedVectorDrawableTarget_animation, 0); if (id != 0) { Animator objectAnimator = AnimatorInflater.loadAnimator(res, theme, id); Animator objectAnimator = AnimatorInflater.loadAnimator(res, theme, id, pathErrorScale); setupAnimatorsForTarget(target, objectAnimator); } a.recycle(); Loading
graphics/java/android/graphics/drawable/VectorDrawable.java +23 −0 Original line number Diff line number Diff line Loading @@ -368,6 +368,29 @@ public class VectorDrawable extends Drawable { } } /** * The size of a pixel when scaled from the intrinsic dimension to the viewport dimension. * This is used to calculate the path animation accuracy. * * @hide */ public float getPixelSize() { if (mVectorState == null && mVectorState.mVPathRenderer == null || mVectorState.mVPathRenderer.mBaseWidth == 0 || mVectorState.mVPathRenderer.mBaseHeight == 0 || mVectorState.mVPathRenderer.mViewportHeight == 0 || mVectorState.mVPathRenderer.mViewportWidth == 0) { return 1; // fall back to 1:1 pixel mapping. } float intrinsicWidth = mVectorState.mVPathRenderer.mBaseWidth; float intrinsicHeight = mVectorState.mVPathRenderer.mBaseHeight; float viewportWidth = mVectorState.mVPathRenderer.mViewportWidth; float viewportHeight = mVectorState.mVPathRenderer.mViewportHeight; float scaleX = viewportWidth / intrinsicWidth; float scaleY = viewportHeight / intrinsicHeight; return Math.min(scaleX, scaleY); } /** @hide */ public static VectorDrawable create(Resources resources, int rid) { try { Loading