diff options
22 files changed, 1077 insertions, 226 deletions
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java index 933135d..06f5aca 100644 --- a/core/java/android/animation/AnimatorInflater.java +++ b/core/java/android/animation/AnimatorInflater.java @@ -17,6 +17,7 @@ package android.animation; import android.content.Context; import android.content.res.Resources; +import android.content.res.Resources.Theme; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.content.res.Resources.NotFoundException; @@ -25,6 +26,9 @@ import android.util.StateSet; import android.util.TypedValue; import android.util.Xml; import android.view.animation.AnimationUtils; + +import com.android.internal.R; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -66,11 +70,26 @@ public class AnimatorInflater { */ public static Animator loadAnimator(Context context, int id) throws NotFoundException { + return loadAnimator(context.getResources(), context.getTheme(), id); + } + + /** + * Loads an {@link Animator} object from a resource + * + * @param resources The resources + * @param theme The theme + * @param id The resource id of the animation to load + * @return The animator object reference by the specified id + * @throws android.content.res.Resources.NotFoundException when the animation cannot be loaded + * @hide + */ + public static Animator loadAnimator(Resources resources, Theme theme, int id) + throws NotFoundException { XmlResourceParser parser = null; try { - parser = context.getResources().getAnimation(id); - return createAnimatorFromXml(context, parser); + parser = resources.getAnimation(id); + return createAnimatorFromXml(resources, theme, parser); } catch (XmlPullParserException ex) { Resources.NotFoundException rnf = new Resources.NotFoundException("Can't load animation resource ID #0x" + @@ -150,7 +169,8 @@ public class AnimatorInflater { } if (animator == null) { - animator = createAnimatorFromXml(context, parser); + animator = createAnimatorFromXml(context.getResources(), + context.getTheme(), parser); } if (animator == null) { @@ -166,103 +186,8 @@ public class AnimatorInflater { } } - private static Animator createAnimatorFromXml(Context c, XmlPullParser parser) - throws XmlPullParserException, IOException { - return createAnimatorFromXml(c, parser, Xml.asAttributeSet(parser), null, 0); - } - - private static Animator createAnimatorFromXml(Context c, XmlPullParser parser, - AttributeSet attrs, AnimatorSet parent, int sequenceOrdering) - throws XmlPullParserException, IOException { - - Animator anim = null; - ArrayList<Animator> childAnims = null; - - // Make sure we are on a start tag. - int type; - int depth = parser.getDepth(); - - while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) - && type != XmlPullParser.END_DOCUMENT) { - - if (type != XmlPullParser.START_TAG) { - continue; - } - - String name = parser.getName(); - - if (name.equals("objectAnimator")) { - anim = loadObjectAnimator(c, attrs); - } else if (name.equals("animator")) { - anim = loadAnimator(c, attrs, null); - } else if (name.equals("set")) { - anim = new AnimatorSet(); - TypedArray a = c.obtainStyledAttributes(attrs, - com.android.internal.R.styleable.AnimatorSet); - int ordering = a.getInt(com.android.internal.R.styleable.AnimatorSet_ordering, - TOGETHER); - createAnimatorFromXml(c, parser, attrs, (AnimatorSet) anim, ordering); - a.recycle(); - } else { - throw new RuntimeException("Unknown animator name: " + parser.getName()); - } - - if (parent != null) { - if (childAnims == null) { - childAnims = new ArrayList<Animator>(); - } - childAnims.add(anim); - } - } - if (parent != null && childAnims != null) { - Animator[] animsArray = new Animator[childAnims.size()]; - int index = 0; - for (Animator a : childAnims) { - animsArray[index++] = a; - } - if (sequenceOrdering == TOGETHER) { - parent.playTogether(animsArray); - } else { - parent.playSequentially(animsArray); - } - } - - return anim; - - } - - private static ObjectAnimator loadObjectAnimator(Context context, AttributeSet attrs) - throws NotFoundException { - - ObjectAnimator anim = new ObjectAnimator(); - - loadAnimator(context, attrs, anim); - - TypedArray a = - context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.PropertyAnimator); - - String propertyName = a.getString(com.android.internal.R.styleable.PropertyAnimator_propertyName); - - anim.setPropertyName(propertyName); - - a.recycle(); - - return anim; - } - - /** - * Creates a new animation whose parameters come from the specified context and - * attributes set. - * - * @param context the application environment - * @param attrs the set of attributes holding the animation parameters - */ - private static ValueAnimator loadAnimator(Context context, AttributeSet attrs, ValueAnimator anim) - throws NotFoundException { - - TypedArray a = - context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Animator); + private static void parseAnimatorFromTypeArray(ValueAnimator anim, TypedArray a) { long duration = a.getInt(com.android.internal.R.styleable.Animator_duration, 300); long startDelay = a.getInt(com.android.internal.R.styleable.Animator_startOffset, 0); @@ -378,11 +303,123 @@ public class AnimatorInflater { if (evaluator != null) { anim.setEvaluator(evaluator); } + } + + private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser) + throws XmlPullParserException, IOException { + return createAnimatorFromXml(res, theme, parser, Xml.asAttributeSet(parser), null, 0); + } + + private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser, + AttributeSet attrs, AnimatorSet parent, int sequenceOrdering) + throws XmlPullParserException, IOException { + + Animator anim = null; + ArrayList<Animator> childAnims = null; + + // Make sure we are on a start tag. + int type; + int depth = parser.getDepth(); + + while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) + && type != XmlPullParser.END_DOCUMENT) { + + if (type != XmlPullParser.START_TAG) { + continue; + } + + String name = parser.getName(); + + if (name.equals("objectAnimator")) { + anim = loadObjectAnimator(res, theme, attrs); + } else if (name.equals("animator")) { + anim = loadAnimator(res, theme, attrs, null); + } else if (name.equals("set")) { + anim = new AnimatorSet(); + TypedArray a; + if (theme != null) { + a = theme.obtainStyledAttributes(attrs, com.android.internal.R.styleable.AnimatorSet, 0, 0); + } else { + a = res.obtainAttributes(attrs, com.android.internal.R.styleable.AnimatorSet); + } + int ordering = a.getInt(com.android.internal.R.styleable.AnimatorSet_ordering, + TOGETHER); + createAnimatorFromXml(res, theme, parser, attrs, (AnimatorSet) anim, ordering); + a.recycle(); + } else { + throw new RuntimeException("Unknown animator name: " + parser.getName()); + } + + if (parent != null) { + if (childAnims == null) { + childAnims = new ArrayList<Animator>(); + } + childAnims.add(anim); + } + } + if (parent != null && childAnims != null) { + Animator[] animsArray = new Animator[childAnims.size()]; + int index = 0; + for (Animator a : childAnims) { + animsArray[index++] = a; + } + if (sequenceOrdering == TOGETHER) { + parent.playTogether(animsArray); + } else { + parent.playSequentially(animsArray); + } + } + + return anim; + + } + + private static ObjectAnimator loadObjectAnimator(Resources res, Theme theme, AttributeSet attrs) + throws NotFoundException { + ObjectAnimator anim = new ObjectAnimator(); + + loadAnimator(res, theme, attrs, anim); + + TypedArray a; + if (theme != null) { + a = theme.obtainStyledAttributes(attrs, R.styleable.PropertyAnimator, 0, 0); + } else { + a = res.obtainAttributes(attrs, R.styleable.PropertyAnimator); + } + + String propertyName = a.getString(R.styleable.PropertyAnimator_propertyName); + + anim.setPropertyName(propertyName); + + a.recycle(); + + return anim; + } + + /** + * Creates a new animation whose parameters come from the specified context + * and attributes set. + * + * @param res The resources + * @param attrs The set of attributes holding the animation parameters + */ + private static ValueAnimator loadAnimator(Resources res, Theme theme, + AttributeSet attrs, ValueAnimator anim) + throws NotFoundException { + + TypedArray a; + if (theme != null) { + a = theme.obtainStyledAttributes(attrs, R.styleable.Animator, 0, 0); + } else { + a = res.obtainAttributes(attrs, R.styleable.Animator); + } + + parseAnimatorFromTypeArray(anim, a); final int resID = a.getResourceId(com.android.internal.R.styleable.Animator_interpolator, 0); if (resID > 0) { - anim.setInterpolator(AnimationUtils.loadInterpolator(context, resID)); + anim.setInterpolator(AnimationUtils.loadInterpolator(res, theme, resID)); } a.recycle(); diff --git a/core/java/android/view/animation/AccelerateInterpolator.java b/core/java/android/view/animation/AccelerateInterpolator.java index c08f348..1c75f16 100644 --- a/core/java/android/view/animation/AccelerateInterpolator.java +++ b/core/java/android/view/animation/AccelerateInterpolator.java @@ -17,15 +17,18 @@ package android.view.animation; import android.content.Context; +import android.content.res.Resources; +import android.content.res.Resources.Theme; import android.content.res.TypedArray; import android.util.AttributeSet; +import com.android.internal.R; import com.android.internal.view.animation.HasNativeInterpolator; import com.android.internal.view.animation.NativeInterpolatorFactory; import com.android.internal.view.animation.NativeInterpolatorFactoryHelper; /** - * An interpolator where the rate of change starts out slowly and + * An interpolator where the rate of change starts out slowly and * and then accelerates. * */ @@ -38,10 +41,10 @@ public class AccelerateInterpolator implements Interpolator, NativeInterpolatorF mFactor = 1.0f; mDoubleFactor = 2.0; } - + /** * Constructor - * + * * @param factor Degree to which the animation should be eased. Seting * factor to 1.0f produces a y=x^2 parabola. Increasing factor above * 1.0f exaggerates the ease-in effect (i.e., it starts even @@ -51,17 +54,26 @@ public class AccelerateInterpolator implements Interpolator, NativeInterpolatorF mFactor = factor; mDoubleFactor = 2 * mFactor; } - + public AccelerateInterpolator(Context context, AttributeSet attrs) { - TypedArray a = - context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.AccelerateInterpolator); - - mFactor = a.getFloat(com.android.internal.R.styleable.AccelerateInterpolator_factor, 1.0f); + this(context.getResources(), context.getTheme(), attrs); + } + + /** @hide */ + public AccelerateInterpolator(Resources res, Theme theme, AttributeSet attrs) { + TypedArray a; + if (theme != null) { + a = theme.obtainStyledAttributes(attrs, R.styleable.AccelerateInterpolator, 0, 0); + } else { + a = res.obtainAttributes(attrs, R.styleable.AccelerateInterpolator); + } + + mFactor = a.getFloat(R.styleable.AccelerateInterpolator_factor, 1.0f); mDoubleFactor = 2 * mFactor; a.recycle(); } - + public float getInterpolation(float input) { if (mFactor == 1.0f) { return input * input; diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java index 1d1fa1e..af4e04f 100644 --- a/core/java/android/view/animation/AnimationUtils.java +++ b/core/java/android/view/animation/AnimationUtils.java @@ -20,6 +20,8 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import android.content.Context; +import android.content.res.Resources; +import android.content.res.Resources.Theme; import android.content.res.XmlResourceParser; import android.content.res.Resources.NotFoundException; import android.util.AttributeSet; @@ -143,7 +145,7 @@ public class AnimationUtils { */ public static LayoutAnimationController loadLayoutAnimation(Context context, int id) throws NotFoundException { - + XmlResourceParser parser = null; try { parser = context.getResources().getAnimation(id); @@ -201,7 +203,7 @@ public class AnimationUtils { /** * Make an animation for objects becoming visible. Uses a slide and fade * effect. - * + * * @param c Context for loading resources * @param fromLeft is the object to be animated coming from the left * @return The new animation @@ -218,11 +220,11 @@ public class AnimationUtils { a.setStartTime(currentAnimationTimeMillis()); return a; } - + /** * Make an animation for objects becoming invisible. Uses a slide and fade * effect. - * + * * @param c Context for loading resources * @param toRight is the object to be animated exiting to the right * @return The new animation @@ -234,17 +236,17 @@ public class AnimationUtils { } else { a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_out_left); } - + a.setInterpolator(new AccelerateInterpolator()); a.setStartTime(currentAnimationTimeMillis()); return a; } - + /** * Make an animation for objects becoming visible. Uses a slide up and fade * effect. - * + * * @param c Context for loading resources * @return The new animation */ @@ -255,10 +257,10 @@ public class AnimationUtils { a.setStartTime(currentAnimationTimeMillis()); return a; } - + /** * Loads an {@link Interpolator} object from a resource - * + * * @param context Application context used to access resources * @param id The resource id of the animation to load * @return The animation object reference by the specified id @@ -268,7 +270,7 @@ public class AnimationUtils { XmlResourceParser parser = null; try { parser = context.getResources().getAnimation(id); - return createInterpolatorFromXml(context, parser); + return createInterpolatorFromXml(context.getResources(), context.getTheme(), parser); } catch (XmlPullParserException ex) { NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" + Integer.toHexString(id)); @@ -284,54 +286,84 @@ public class AnimationUtils { } } - - private static Interpolator createInterpolatorFromXml(Context c, XmlPullParser parser) + + /** + * Loads an {@link Interpolator} object from a resource + * + * @param res The resources + * @param id The resource id of the animation to load + * @return The interpolator object reference by the specified id + * @throws NotFoundException + * @hide + */ + public static Interpolator loadInterpolator(Resources res, Theme theme, int id) throws NotFoundException { + XmlResourceParser parser = null; + try { + parser = res.getAnimation(id); + return createInterpolatorFromXml(res, theme, parser); + } catch (XmlPullParserException ex) { + NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" + + Integer.toHexString(id)); + rnf.initCause(ex); + throw rnf; + } catch (IOException ex) { + NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" + + Integer.toHexString(id)); + rnf.initCause(ex); + throw rnf; + } finally { + if (parser != null) + parser.close(); + } + + } + + private static Interpolator createInterpolatorFromXml(Resources res, Theme theme, XmlPullParser parser) throws XmlPullParserException, IOException { - + Interpolator interpolator = null; - + // Make sure we are on a start tag. int type; int depth = parser.getDepth(); - while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) - && type != XmlPullParser.END_DOCUMENT) { + while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) + && type != XmlPullParser.END_DOCUMENT) { if (type != XmlPullParser.START_TAG) { continue; } AttributeSet attrs = Xml.asAttributeSet(parser); - - String name = parser.getName(); - - + + String name = parser.getName(); + if (name.equals("linearInterpolator")) { - interpolator = new LinearInterpolator(c, attrs); + interpolator = new LinearInterpolator(); } else if (name.equals("accelerateInterpolator")) { - interpolator = new AccelerateInterpolator(c, attrs); + interpolator = new AccelerateInterpolator(res, theme, attrs); } else if (name.equals("decelerateInterpolator")) { - interpolator = new DecelerateInterpolator(c, attrs); - } else if (name.equals("accelerateDecelerateInterpolator")) { - interpolator = new AccelerateDecelerateInterpolator(c, attrs); - } else if (name.equals("cycleInterpolator")) { - interpolator = new CycleInterpolator(c, attrs); + interpolator = new DecelerateInterpolator(res, theme, attrs); + } else if (name.equals("accelerateDecelerateInterpolator")) { + interpolator = new AccelerateDecelerateInterpolator(); + } else if (name.equals("cycleInterpolator")) { + interpolator = new CycleInterpolator(res, theme, attrs); } else if (name.equals("anticipateInterpolator")) { - interpolator = new AnticipateInterpolator(c, attrs); + interpolator = new AnticipateInterpolator(res, theme, attrs); } else if (name.equals("overshootInterpolator")) { - interpolator = new OvershootInterpolator(c, attrs); + interpolator = new OvershootInterpolator(res, theme, attrs); } else if (name.equals("anticipateOvershootInterpolator")) { - interpolator = new AnticipateOvershootInterpolator(c, attrs); + interpolator = new AnticipateOvershootInterpolator(res, theme, attrs); } else if (name.equals("bounceInterpolator")) { - interpolator = new BounceInterpolator(c, attrs); + interpolator = new BounceInterpolator(); } else if (name.equals("pathInterpolator")) { - interpolator = new PathInterpolator(c, attrs); + interpolator = new PathInterpolator(res, theme, attrs); } else { throw new RuntimeException("Unknown interpolator name: " + parser.getName()); } } - + return interpolator; } diff --git a/core/java/android/view/animation/AnticipateInterpolator.java b/core/java/android/view/animation/AnticipateInterpolator.java index 83a8007..fe756bd 100644 --- a/core/java/android/view/animation/AnticipateInterpolator.java +++ b/core/java/android/view/animation/AnticipateInterpolator.java @@ -17,9 +17,12 @@ package android.view.animation; import android.content.Context; +import android.content.res.Resources; import android.content.res.TypedArray; +import android.content.res.Resources.Theme; import android.util.AttributeSet; +import com.android.internal.R; import com.android.internal.view.animation.HasNativeInterpolator; import com.android.internal.view.animation.NativeInterpolatorFactory; import com.android.internal.view.animation.NativeInterpolatorFactoryHelper; @@ -45,11 +48,20 @@ public class AnticipateInterpolator implements Interpolator, NativeInterpolatorF } public AnticipateInterpolator(Context context, AttributeSet attrs) { - TypedArray a = context.obtainStyledAttributes(attrs, - com.android.internal.R.styleable.AnticipateInterpolator); + this(context.getResources(), context.getTheme(), attrs); + } + + /** @hide */ + public AnticipateInterpolator(Resources res, Theme theme, AttributeSet attrs) { + TypedArray a; + if (theme != null) { + a = theme.obtainStyledAttributes(attrs, R.styleable.AnticipateInterpolator, 0, 0); + } else { + a = res.obtainAttributes(attrs, R.styleable.AnticipateInterpolator); + } mTension = - a.getFloat(com.android.internal.R.styleable.AnticipateInterpolator_tension, 2.0f); + a.getFloat(R.styleable.AnticipateInterpolator_tension, 2.0f); a.recycle(); } diff --git a/core/java/android/view/animation/AnticipateOvershootInterpolator.java b/core/java/android/view/animation/AnticipateOvershootInterpolator.java index 1a8adfd..78e5acf 100644 --- a/core/java/android/view/animation/AnticipateOvershootInterpolator.java +++ b/core/java/android/view/animation/AnticipateOvershootInterpolator.java @@ -17,6 +17,8 @@ package android.view.animation; import android.content.Context; +import android.content.res.Resources; +import android.content.res.Resources.Theme; import android.content.res.TypedArray; import android.util.AttributeSet; @@ -62,7 +64,17 @@ public class AnticipateOvershootInterpolator implements Interpolator, NativeInte } public AnticipateOvershootInterpolator(Context context, AttributeSet attrs) { - TypedArray a = context.obtainStyledAttributes(attrs, AnticipateOvershootInterpolator); + this(context.getResources(), context.getTheme(), attrs); + } + + /** @hide */ + public AnticipateOvershootInterpolator(Resources res, Theme theme, AttributeSet attrs) { + TypedArray a; + if (theme != null) { + a = theme.obtainStyledAttributes(attrs, AnticipateOvershootInterpolator, 0, 0); + } else { + a = res.obtainAttributes(attrs, AnticipateOvershootInterpolator); + } mTension = a.getFloat(AnticipateOvershootInterpolator_tension, 2.0f) * a.getFloat(AnticipateOvershootInterpolator_extraTension, 1.5f); diff --git a/core/java/android/view/animation/CycleInterpolator.java b/core/java/android/view/animation/CycleInterpolator.java index d1ebf05..3114aa3 100644 --- a/core/java/android/view/animation/CycleInterpolator.java +++ b/core/java/android/view/animation/CycleInterpolator.java @@ -17,9 +17,12 @@ package android.view.animation; import android.content.Context; +import android.content.res.Resources; import android.content.res.TypedArray; +import android.content.res.Resources.Theme; import android.util.AttributeSet; +import com.android.internal.R; import com.android.internal.view.animation.HasNativeInterpolator; import com.android.internal.view.animation.NativeInterpolatorFactory; import com.android.internal.view.animation.NativeInterpolatorFactoryHelper; @@ -34,20 +37,29 @@ public class CycleInterpolator implements Interpolator, NativeInterpolatorFactor public CycleInterpolator(float cycles) { mCycles = cycles; } - + public CycleInterpolator(Context context, AttributeSet attrs) { - TypedArray a = - context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.CycleInterpolator); - - mCycles = a.getFloat(com.android.internal.R.styleable.CycleInterpolator_cycles, 1.0f); - + this(context.getResources(), context.getTheme(), attrs); + } + + /** @hide */ + public CycleInterpolator(Resources resources, Theme theme, AttributeSet attrs) { + TypedArray a; + if (theme != null) { + a = theme.obtainStyledAttributes(attrs, R.styleable.CycleInterpolator, 0, 0); + } else { + a = resources.obtainAttributes(attrs, R.styleable.CycleInterpolator); + } + + mCycles = a.getFloat(R.styleable.CycleInterpolator_cycles, 1.0f); + a.recycle(); } - + public float getInterpolation(float input) { return (float)(Math.sin(2 * mCycles * Math.PI * input)); } - + private float mCycles; /** @hide */ diff --git a/core/java/android/view/animation/DecelerateInterpolator.java b/core/java/android/view/animation/DecelerateInterpolator.java index 0789a0e..674207c 100644 --- a/core/java/android/view/animation/DecelerateInterpolator.java +++ b/core/java/android/view/animation/DecelerateInterpolator.java @@ -17,15 +17,18 @@ package android.view.animation; import android.content.Context; +import android.content.res.Resources; import android.content.res.TypedArray; +import android.content.res.Resources.Theme; import android.util.AttributeSet; +import com.android.internal.R; import com.android.internal.view.animation.HasNativeInterpolator; import com.android.internal.view.animation.NativeInterpolatorFactory; import com.android.internal.view.animation.NativeInterpolatorFactoryHelper; /** - * An interpolator where the rate of change starts out quickly and + * An interpolator where the rate of change starts out quickly and * and then decelerates. * */ @@ -36,7 +39,7 @@ public class DecelerateInterpolator implements Interpolator, NativeInterpolatorF /** * Constructor - * + * * @param factor Degree to which the animation should be eased. Setting factor to 1.0f produces * an upside-down y=x^2 parabola. Increasing factor above 1.0f makes exaggerates the * ease-out effect (i.e., it starts even faster and ends evens slower) @@ -44,16 +47,25 @@ public class DecelerateInterpolator implements Interpolator, NativeInterpolatorF public DecelerateInterpolator(float factor) { mFactor = factor; } - + public DecelerateInterpolator(Context context, AttributeSet attrs) { - TypedArray a = - context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.DecelerateInterpolator); - - mFactor = a.getFloat(com.android.internal.R.styleable.DecelerateInterpolator_factor, 1.0f); - + this(context.getResources(), context.getTheme(), attrs); + } + + /** @hide */ + public DecelerateInterpolator(Resources res, Theme theme, AttributeSet attrs) { + TypedArray a; + if (theme != null) { + a = theme.obtainStyledAttributes(attrs, R.styleable.DecelerateInterpolator, 0, 0); + } else { + a = res.obtainAttributes(attrs, R.styleable.DecelerateInterpolator); + } + + mFactor = a.getFloat(R.styleable.DecelerateInterpolator_factor, 1.0f); + a.recycle(); } - + public float getInterpolation(float input) { float result; if (mFactor == 1.0f) { @@ -63,7 +75,7 @@ public class DecelerateInterpolator implements Interpolator, NativeInterpolatorF } return result; } - + private float mFactor = 1.0f; /** @hide */ diff --git a/core/java/android/view/animation/OvershootInterpolator.java b/core/java/android/view/animation/OvershootInterpolator.java index a2466f1..d6c2808 100644 --- a/core/java/android/view/animation/OvershootInterpolator.java +++ b/core/java/android/view/animation/OvershootInterpolator.java @@ -17,9 +17,12 @@ package android.view.animation; import android.content.Context; +import android.content.res.Resources; +import android.content.res.Resources.Theme; import android.content.res.TypedArray; import android.util.AttributeSet; +import com.android.internal.R; import com.android.internal.view.animation.HasNativeInterpolator; import com.android.internal.view.animation.NativeInterpolatorFactory; import com.android.internal.view.animation.NativeInterpolatorFactoryHelper; @@ -46,11 +49,20 @@ public class OvershootInterpolator implements Interpolator, NativeInterpolatorFa } public OvershootInterpolator(Context context, AttributeSet attrs) { - TypedArray a = context.obtainStyledAttributes(attrs, - com.android.internal.R.styleable.OvershootInterpolator); + this(context.getResources(), context.getTheme(), attrs); + } + + /** @hide */ + public OvershootInterpolator(Resources res, Theme theme, AttributeSet attrs) { + TypedArray a; + if (theme != null) { + a = theme.obtainStyledAttributes(attrs, R.styleable.OvershootInterpolator, 0, 0); + } else { + a = res.obtainAttributes(attrs, R.styleable.OvershootInterpolator); + } mTension = - a.getFloat(com.android.internal.R.styleable.OvershootInterpolator_tension, 2.0f); + a.getFloat(R.styleable.OvershootInterpolator_tension, 2.0f); a.recycle(); } diff --git a/core/java/android/view/animation/PathInterpolator.java b/core/java/android/view/animation/PathInterpolator.java index a369509..da12ffb 100644 --- a/core/java/android/view/animation/PathInterpolator.java +++ b/core/java/android/view/animation/PathInterpolator.java @@ -16,11 +16,15 @@ package android.view.animation; import android.content.Context; +import android.content.res.Resources; +import android.content.res.Resources.Theme; import android.content.res.TypedArray; import android.graphics.Path; import android.util.AttributeSet; import android.view.InflateException; +import com.android.internal.R; + /** * An interpolator that can traverse a Path that extends from <code>Point</code> * <code>(0, 0)</code> to <code>(1, 1)</code>. The x coordinate along the <code>Path</code> @@ -81,18 +85,33 @@ public class PathInterpolator implements Interpolator { } public PathInterpolator(Context context, AttributeSet attrs) { - TypedArray a = context.obtainStyledAttributes(attrs, - com.android.internal.R.styleable.PathInterpolator); - if (!a.hasValue(com.android.internal.R.styleable.PathInterpolator_controlX1)) { + this(context.getResources(), context.getTheme(), attrs); + } + + /** @hide */ + public PathInterpolator(Resources res, Theme theme, AttributeSet attrs) { + TypedArray a; + if (theme != null) { + a = theme.obtainStyledAttributes(attrs, R.styleable.PathInterpolator, 0, 0); + } else { + a = res.obtainAttributes(attrs, R.styleable.PathInterpolator); + } + parseInterpolatorFromTypeArray(a); + + a.recycle(); + } + + private void parseInterpolatorFromTypeArray(TypedArray a) { + if (!a.hasValue(R.styleable.PathInterpolator_controlX1)) { throw new InflateException("pathInterpolator requires the controlX1 attribute"); - } else if (!a.hasValue(com.android.internal.R.styleable.PathInterpolator_controlY1)) { + } else if (!a.hasValue(R.styleable.PathInterpolator_controlY1)) { throw new InflateException("pathInterpolator requires the controlY1 attribute"); } - float x1 = a.getFloat(com.android.internal.R.styleable.PathInterpolator_controlX1, 0); - float y1 = a.getFloat(com.android.internal.R.styleable.PathInterpolator_controlY1, 0); + float x1 = a.getFloat(R.styleable.PathInterpolator_controlX1, 0); + float y1 = a.getFloat(R.styleable.PathInterpolator_controlY1, 0); - boolean hasX2 = a.hasValue(com.android.internal.R.styleable.PathInterpolator_controlX2); - boolean hasY2 = a.hasValue(com.android.internal.R.styleable.PathInterpolator_controlY2); + boolean hasX2 = a.hasValue(R.styleable.PathInterpolator_controlX2); + boolean hasY2 = a.hasValue(R.styleable.PathInterpolator_controlY2); if (hasX2 != hasY2) { throw new InflateException( @@ -102,12 +121,10 @@ public class PathInterpolator implements Interpolator { if (!hasX2) { initQuad(x1, y1); } else { - float x2 = a.getFloat(com.android.internal.R.styleable.PathInterpolator_controlX2, 0); - float y2 = a.getFloat(com.android.internal.R.styleable.PathInterpolator_controlY2, 0); + float x2 = a.getFloat(R.styleable.PathInterpolator_controlX2, 0); + float y2 = a.getFloat(R.styleable.PathInterpolator_controlY2, 0); initCubic(x1, y1, x2, y2); } - - a.recycle(); } private void initQuad(float controlX, float controlY) { diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 2fea91e..aa4b3dc 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -4772,7 +4772,7 @@ </declare-styleable> <!-- ========================== --> - <!-- Vector drawable class --> + <!-- VectorDrawable class --> <!-- ========================== --> <eat-comment /> @@ -4792,7 +4792,7 @@ <attr name="height" /> </declare-styleable> - <!-- Defines the group used in Vector Drawables. --> + <!-- Defines the group used in VectorDrawables. --> <declare-styleable name="VectorDrawableGroup"> <!-- The Name of this group --> <attr name="name" /> @@ -4814,7 +4814,7 @@ <attr name="alpha" /> </declare-styleable> - <!-- Defines the path used in Vector Drawables. --> + <!-- Defines the path used in VectorDrawables. --> <declare-styleable name="VectorDrawablePath"> <!-- The Name of this path --> <attr name="name" /> @@ -4855,6 +4855,25 @@ </declare-styleable> <!-- ========================== --> + <!-- AnimatedVectorDrawable class --> + <!-- ========================== --> + <eat-comment /> + + <!-- Define the AnimatedVectorDrawable. --> + <declare-styleable name="AnimatedVectorDrawable"> + <!-- The static vector drawable. --> + <attr name="drawable" /> + </declare-styleable> + + <!-- Defines the target path or group used in the AnimatedVectorDrawable. --> + <declare-styleable name="AnimatedVectorDrawableTarget"> + <!-- The name of this target path or group --> + <attr name="name" /> + <!-- The animation for this target path or group --> + <attr name="animation" /> + </declare-styleable> + + <!-- ========================== --> <!-- Animation class attributes --> <!-- ========================== --> <eat-comment /> diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java new file mode 100644 index 0000000..968c0ec --- /dev/null +++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2014 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.graphics.drawable; + +import android.animation.Animator; +import android.animation.AnimatorInflater; +import android.content.res.Resources; +import android.content.res.Resources.Theme; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.util.Log; + +import com.android.internal.R; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.ArrayList; + +/** + * AnimatedVectorDrawable can use ObjectAnimator and AnimatorSet to animate + * the property of the VectorDrawable. + * + * @hide + */ +public class AnimatedVectorDrawable extends Drawable implements Animatable { + private static final String LOGTAG = AnimatedVectorDrawable.class.getSimpleName(); + + private static final String ANIMATED_VECTOR = "animated-vector"; + private static final String TARGET = "target"; + + private static final boolean DBG_ANIMATION_VECTOR_DRAWABLE = false; + + private final AnimatedVectorDrawableState mAnimatedVectorState; + + + public AnimatedVectorDrawable() { + mAnimatedVectorState = new AnimatedVectorDrawableState( + new AnimatedVectorDrawableState(null)); + } + + private AnimatedVectorDrawable(AnimatedVectorDrawableState state, Resources res, + Theme theme) { + // TODO: Correctly handle the constant state for AVD. + mAnimatedVectorState = new AnimatedVectorDrawableState(state); + if (theme != null && canApplyTheme()) { + applyTheme(theme); + } + } + + @Override + public ConstantState getConstantState() { + return null; + } + + @Override + public void draw(Canvas canvas) { + mAnimatedVectorState.mVectorDrawable.draw(canvas); + if (isRunning()) { + invalidateSelf(); + } + } + + @Override + protected void onBoundsChange(Rect bounds) { + mAnimatedVectorState.mVectorDrawable.setBounds(bounds); + } + + @Override + public int getAlpha() { + return mAnimatedVectorState.mVectorDrawable.getAlpha(); + } + + @Override + public void setAlpha(int alpha) { + mAnimatedVectorState.mVectorDrawable.setAlpha(alpha); + } + + @Override + public void setColorFilter(ColorFilter colorFilter) { + mAnimatedVectorState.mVectorDrawable.setColorFilter(colorFilter); + } + + @Override + public int getOpacity() { + return mAnimatedVectorState.mVectorDrawable.getOpacity(); + } + + @Override + public int getIntrinsicWidth() { + return mAnimatedVectorState.mVectorDrawable.getIntrinsicWidth(); + } + + @Override + public int getIntrinsicHeight() { + return mAnimatedVectorState.mVectorDrawable.getIntrinsicHeight(); + } + + @Override + public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme) + throws XmlPullParserException, IOException { + + int eventType = parser.getEventType(); + while (eventType != XmlPullParser.END_DOCUMENT) { + if (eventType == XmlPullParser.START_TAG) { + final String tagName = parser.getName(); + if (ANIMATED_VECTOR.equals(tagName)) { + final TypedArray a = obtainAttributes(res, theme, attrs, + R.styleable.AnimatedVectorDrawable); + int drawableRes = a.getResourceId( + R.styleable.AnimatedVectorDrawable_drawable, 0); + if (drawableRes != 0) { + mAnimatedVectorState.mVectorDrawable = (VectorDrawable) res.getDrawable( + drawableRes); + } + a.recycle(); + } else if (TARGET.equals(tagName)) { + final TypedArray a = obtainAttributes(res, theme, attrs, + R.styleable.AnimatedVectorDrawableTarget); + final String target = a.getString( + R.styleable.AnimatedVectorDrawableTarget_name); + + int id = a.getResourceId( + R.styleable.AnimatedVectorDrawableTarget_animation, 0); + if (id != 0) { + Animator objectAnimator = AnimatorInflater.loadAnimator(res, theme, id); + setupAnimatorsForTarget(target, objectAnimator); + } + a.recycle(); + } + } + + eventType = parser.next(); + } + } + + @Override + public boolean canApplyTheme() { + return super.canApplyTheme() || mAnimatedVectorState != null + && mAnimatedVectorState.canApplyTheme(); + } + + @Override + public void applyTheme(Theme t) { + super.applyTheme(t); + + final VectorDrawable vectorDrawable = mAnimatedVectorState.mVectorDrawable; + if (vectorDrawable != null && vectorDrawable.canApplyTheme()) { + vectorDrawable.applyTheme(t); + } + } + + private static class AnimatedVectorDrawableState extends ConstantState { + int mChangingConfigurations; + VectorDrawable mVectorDrawable; + ArrayList<Animator> mAnimators; + + public AnimatedVectorDrawableState(AnimatedVectorDrawableState copy) { + if (copy != null) { + mChangingConfigurations = copy.mChangingConfigurations; + // TODO: Make sure the constant state are handled correctly. + mVectorDrawable = new VectorDrawable(); + mAnimators = new ArrayList<Animator>(); + } + } + + @Override + public Drawable newDrawable() { + return new AnimatedVectorDrawable(this, null, null); + } + + @Override + public Drawable newDrawable(Resources res) { + return new AnimatedVectorDrawable(this, res, null); + } + + @Override + public Drawable newDrawable(Resources res, Theme theme) { + return new AnimatedVectorDrawable(this, res, theme); + } + + @Override + public int getChangingConfigurations() { + return mChangingConfigurations; + } + } + + private void setupAnimatorsForTarget(String name, Animator animator) { + Object target = mAnimatedVectorState.mVectorDrawable.getTargetByName(name); + animator.setTarget(target); + mAnimatedVectorState.mAnimators.add(animator); + if (DBG_ANIMATION_VECTOR_DRAWABLE) { + Log.v(LOGTAG, "add animator for target " + name + " " + animator); + } + } + + @Override + public boolean isRunning() { + final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators; + final int size = animators.size(); + for (int i = 0; i < size; i++) { + final Animator animator = animators.get(i); + if (animator.isRunning()) { + return true; + } + } + return false; + } + + @Override + public void start() { + final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators; + final int size = animators.size(); + for (int i = 0; i < size; i++) { + final Animator animator = animators.get(i); + if (animator.isPaused()) { + animator.resume(); + } else if (!animator.isRunning()) { + animator.start(); + } + } + invalidateSelf(); + } + + @Override + public void stop() { + final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators; + final int size = animators.size(); + for (int i = 0; i < size; i++) { + final Animator animator = animators.get(i); + animator.pause(); + } + } +} diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index 18e8e52..6a7757b 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -209,7 +209,7 @@ public abstract class Drawable { * stored bounds of this drawable. * * @see #copyBounds() - * @see #copyBounds(android.graphics.Rect) + * @see #copyBounds(android.graphics.Rect) */ public final Rect getBounds() { if (mBounds == ZERO_BOUNDS_RECT) { @@ -328,8 +328,8 @@ public abstract class Drawable { * that want to support animated drawables. * * @param cb The client's Callback implementation. - * - * @see #getCallback() + * + * @see #getCallback() */ public final void setCallback(Callback cb) { mCallback = new WeakReference<Callback>(cb); @@ -338,10 +338,10 @@ public abstract class Drawable { /** * Return the current {@link Callback} implementation attached to this * Drawable. - * + * * @return A {@link Callback} instance or null if no callback was set. - * - * @see #setCallback(android.graphics.drawable.Drawable.Callback) + * + * @see #setCallback(android.graphics.drawable.Drawable.Callback) */ public Callback getCallback() { if (mCallback != null) { @@ -349,15 +349,15 @@ public abstract class Drawable { } return null; } - + /** * Use the current {@link Callback} implementation to have this Drawable * redrawn. Does nothing if there is no Callback attached to the * Drawable. * * @see Callback#invalidateDrawable - * @see #getCallback() - * @see #setCallback(android.graphics.drawable.Drawable.Callback) + * @see #getCallback() + * @see #setCallback(android.graphics.drawable.Drawable.Callback) */ public void invalidateSelf() { final Callback callback = getCallback(); @@ -931,7 +931,7 @@ public abstract class Drawable { Rects only to drop them on the floor. */ Rect pad = new Rect(); - + // Special stuff for compatibility mode: if the target density is not // the same as the display density, but the resource -is- the same as // the display density, then don't scale it down to the target density. @@ -1040,6 +1040,8 @@ public abstract class Drawable { drawable = new GradientDrawable(); } else if (name.equals("vector")) { drawable = new VectorDrawable(); + } else if (name.equals("animated-vector")) { + drawable = new AnimatedVectorDrawable(); } else if (name.equals("scale")) { drawable = new ScaleDrawable(); } else if (name.equals("clip")) { @@ -1047,7 +1049,7 @@ public abstract class Drawable { } else if (name.equals("rotate")) { drawable = new RotateDrawable(); } else if (name.equals("animated-rotate")) { - drawable = new AnimatedRotateDrawable(); + drawable = new AnimatedRotateDrawable(); } else if (name.equals("animation-list")) { drawable = new AnimationDrawable(); } else if (name.equals("inset")) { diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index c6c5b31..c531c22 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -27,6 +27,7 @@ import android.graphics.PathMeasure; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.Region; +import android.util.ArrayMap; import android.util.AttributeSet; import android.util.Log; import android.util.Xml; @@ -40,7 +41,6 @@ import org.xmlpull.v1.XmlPullParserFactory; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.Stack; /** @@ -135,6 +135,8 @@ public class VectorDrawable extends Drawable { private final VectorDrawableState mVectorState; + private final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<String, Object>(); + public VectorDrawable() { mVectorState = new VectorDrawableState(null); } @@ -147,6 +149,10 @@ public class VectorDrawable extends Drawable { } } + Object getTargetByName(String name) { + return mVGTargetsMap.get(name); + } + @Override public ConstantState getConstantState() { return mVectorState; @@ -162,6 +168,11 @@ public class VectorDrawable extends Drawable { } @Override + public int getAlpha() { + return mVectorState.mVPathRenderer.getRootAlpha(); + } + + @Override public void setAlpha(int alpha) { if (mVectorState.mVPathRenderer.getRootAlpha() != alpha) { mVectorState.mVPathRenderer.setRootAlpha(alpha); @@ -302,6 +313,9 @@ public class VectorDrawable extends Drawable { final VPath path = new VPath(); path.inflate(res, attrs, theme); currentGroup.add(path); + if (path.getPathName() != null) { + mVGTargetsMap.put(path.getPathName(), path); + } noPathTag = false; } else if (SHAPE_SIZE.equals(tagName)) { pathRenderer.parseSize(res, attrs); @@ -314,6 +328,9 @@ public class VectorDrawable extends Drawable { newChildGroup.inflate(res, attrs, theme); currentGroup.mChildGroupList.add(newChildGroup); groupStack.push(newChildGroup); + if (newChildGroup.getGroupName() != null) { + mVGTargetsMap.put(newChildGroup.getGroupName(), newChildGroup); + } noGroupTag = false; } } else if (eventType == XmlPullParser.END_TAG) { @@ -363,7 +380,7 @@ public class VectorDrawable extends Drawable { indent += " "; } // Print the current node - Log.v(LOGTAG, indent + "current group is :" + currentGroup.getName() + Log.v(LOGTAG, indent + "current group is :" + currentGroup.getGroupName() + " rotation is " + currentGroup.mRotate); Log.v(LOGTAG, indent + "matrix is :" + currentGroup.getLocalMatrix().toString()); // Then print all the children @@ -672,8 +689,7 @@ public class VectorDrawable extends Drawable { } - private static class VGroup { - private final HashMap<String, VPath> mVGPathMap = new HashMap<String, VPath>(); + static class VGroup { private final ArrayList<VPath> mPathList = new ArrayList<VPath>(); private final ArrayList<VGroup> mChildGroupList = new ArrayList<VGroup>(); @@ -694,10 +710,98 @@ public class VectorDrawable extends Drawable { private int[] mThemeAttrs; - private String mName = null; + private String mGroupName = null; + + /* Getter and Setter */ + public float getRotation() { + return mRotate; + } + + public void setRotation(float rotation) { + if (rotation != mRotate) { + mRotate = rotation; + updateLocalMatrix(); + } + } + + public float getPivotX() { + return mPivotX; + } + + public void setPivotX(float pivotX) { + if (pivotX != mPivotX) { + mPivotX = pivotX; + updateLocalMatrix(); + } + } + + public float getPivotY() { + return mPivotY; + } + + public void setPivotY(float pivotY) { + if (pivotY != mPivotY) { + mPivotY = pivotY; + updateLocalMatrix(); + } + } + + public float getScaleX() { + return mScaleX; + } - public String getName() { - return mName; + public void setScaleX(float scaleX) { + if (scaleX != mScaleX) { + mScaleX = scaleX; + updateLocalMatrix(); + } + } + + public float getScaleY() { + return mScaleY; + } + + public void setScaleY(float scaleY) { + if (scaleY != mScaleY) { + mScaleY = scaleY; + updateLocalMatrix(); + } + } + + public float getTranslateX() { + return mTranslateX; + } + + public void setTranslateX(float translateX) { + if (translateX != mTranslateX) { + mTranslateX = translateX; + updateLocalMatrix(); + } + } + + public float getTranslateY() { + return mTranslateY; + } + + public void setTranslateY(float translateY) { + if (translateY != mTranslateY) { + mTranslateY = translateY; + updateLocalMatrix(); + } + } + + public float getAlpha() { + return mGroupAlpha; + } + + public void setAlpha(float groupAlpha) { + if (groupAlpha != mGroupAlpha) { + mGroupAlpha = groupAlpha; + } + } + + public String getGroupName() { + return mGroupName; } public Matrix getLocalMatrix() { @@ -705,8 +809,6 @@ public class VectorDrawable extends Drawable { } public void add(VPath path) { - String id = path.getID(); - mVGPathMap.put(id, path); mPathList.add(path); } @@ -732,7 +834,7 @@ public class VectorDrawable extends Drawable { mGroupAlpha = a.getFloat(R.styleable.VectorDrawableGroup_alpha, mGroupAlpha); updateLocalMatrix(); if (a.hasValue(R.styleable.VectorDrawableGroup_name)) { - mName = a.getString(R.styleable.VectorDrawableGroup_name); + mGroupName = a.getString(R.styleable.VectorDrawableGroup_name); } a.recycle(); } @@ -774,7 +876,7 @@ public class VectorDrawable extends Drawable { } if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_name] == 0) { - mName = a.getString(R.styleable.VectorDrawableGroup_name); + mGroupName = a.getString(R.styleable.VectorDrawableGroup_name); } if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_alpha] == 0) { @@ -805,19 +907,15 @@ public class VectorDrawable extends Drawable { } - private static class VPath { - private static final int MAX_STATES = 10; - + static class VPath { private int[] mThemeAttrs; int mStrokeColor = 0; float mStrokeWidth = 0; float mStrokeOpacity = Float.NaN; - int mFillColor = Color.BLACK; int mFillRule; float mFillOpacity = Float.NaN; - float mTrimPathStart = 0; float mTrimPathEnd = 1; float mTrimPathOffset = 0; @@ -828,7 +926,7 @@ public class VectorDrawable extends Drawable { float mStrokeMiterlimit = 4; private VNode[] mNode = null; - private String mId; + private String mPathName; public VPath() { // Empty constructor. @@ -841,8 +939,8 @@ public class VectorDrawable extends Drawable { } } - public String getID() { - return mId; + public String getPathName() { + return mPathName; } private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) { @@ -871,6 +969,71 @@ public class VectorDrawable extends Drawable { } } + /* Setters and Getters */ + int getStroke() { + return mStrokeColor; + } + + void setStroke(int strokeColor) { + mStrokeColor = strokeColor; + } + + float getStrokeWidth() { + return mStrokeWidth; + } + + void setStrokeWidth(float strokeWidth) { + mStrokeWidth = strokeWidth; + } + + float getStrokeOpacity() { + return mStrokeOpacity; + } + + void setStrokeOpacity(float strokeOpacity) { + mStrokeOpacity = strokeOpacity; + } + + int getFill() { + return mFillColor; + } + + void setFill(int fillColor) { + mFillColor = fillColor; + } + + float getFillOpacity() { + return mFillOpacity; + } + + void setFillOpacity(float fillOpacity) { + mFillOpacity = fillOpacity; + } + + float getTrimPathStart() { + return mTrimPathStart; + } + + void setTrimPathStart(float trimPathStart) { + mTrimPathStart = trimPathStart; + } + + float getTrimPathEnd() { + return mTrimPathEnd; + } + + void setTrimPathEnd(float trimPathEnd) { + mTrimPathEnd = trimPathEnd; + } + + float getTrimPathOffset() { + return mTrimPathOffset; + } + + void setTrimPathOffset(float trimPathOffset) { + mTrimPathOffset = trimPathOffset; + } + public void inflate(Resources r, AttributeSet attrs, Theme theme) { final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawablePath); final int[] themeAttrs = a.extractThemeAttrs(); @@ -883,7 +1046,7 @@ public class VectorDrawable extends Drawable { } if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_name] == 0) { - mId = a.getString(R.styleable.VectorDrawablePath_name); + mPathName = a.getString(R.styleable.VectorDrawablePath_name); } if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pathData] == 0) { @@ -966,7 +1129,7 @@ public class VectorDrawable extends Drawable { mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip); if (a.hasValue(R.styleable.VectorDrawablePath_name)) { - mId = a.getString(R.styleable.VectorDrawablePath_name); + mPathName = a.getString(R.styleable.VectorDrawablePath_name); } if (a.hasValue(R.styleable.VectorDrawablePath_pathData)) { diff --git a/tests/VectorDrawableTest/AndroidManifest.xml b/tests/VectorDrawableTest/AndroidManifest.xml index 113dce3..db2efc3 100644 --- a/tests/VectorDrawableTest/AndroidManifest.xml +++ b/tests/VectorDrawableTest/AndroidManifest.xml @@ -17,13 +17,13 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.test.dynamic" > + <uses-sdk android:minSdkVersion="20" /> <application android:hardwareAccelerated="true" android:label="vector" > - - <activity + <activity android:name="VectorDrawablePerformance" android:label="Vector Performance" > <intent-filter> @@ -31,13 +31,13 @@ <category android:name="com.android.test.dynamic.TEST" /> </intent-filter> - </activity> <activity android:name="VectorDrawableAnimation" android:label="VectorTestAnimation" > <intent-filter> <action android:name="android.intent.action.MAIN" /> + <category android:name="com.android.test.dynamic.TEST" /> </intent-filter> </activity> @@ -52,6 +52,15 @@ </intent-filter> </activity> <activity + android:name="AnimatedVectorDrawableTest" + android:label="AnimatedVectorDrawableTest" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="com.android.test.dynamic.TEST" /> + </intent-filter> + </activity> + <activity android:name="VectorDrawable01" android:label="VectorTest1" > <intent-filter> @@ -68,7 +77,6 @@ <category android:name="com.android.test.dynamic.TEST" /> </intent-filter> - </activity> <activity android:name="VectorDrawableStaticPerf" @@ -78,9 +86,7 @@ <category android:name="com.android.test.dynamic.TEST" /> </intent-filter> - </activity> - <activity android:name="VectorCheckbox" android:label="On a Checkbox" > @@ -89,7 +95,6 @@ <category android:name="com.android.test.dynamic.TEST" /> </intent-filter> - </activity> <activity android:name="VectorPathChecking" @@ -99,7 +104,6 @@ <category android:name="com.android.test.dynamic.TEST" /> </intent-filter> - </activity> </application> diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation01.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation01.xml new file mode 100644 index 0000000..d47e019 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/trim_path_animation01.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2014 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. +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" > + + <set android:ordering="sequentially" > + <objectAnimator + android:duration="5000" + android:propertyName="trimPathEnd" + android:valueFrom="0" + android:valueTo="1" + android:valueType="floatType" /> + <objectAnimator + android:duration="5000" + android:propertyName="trimPathEnd" + android:valueFrom="1" + android:valueTo="0" + android:valueType="floatType" /> + </set> + +</set>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation02.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation02.xml new file mode 100644 index 0000000..3bf2865 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/trim_path_animation02.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2014 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. +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" > + + <objectAnimator + android:duration="5000" + android:propertyName="fill" + android:valueFrom="#FF000000" + android:valueTo="#FFFF0000"/> + +</set>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation03.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation03.xml new file mode 100644 index 0000000..72beba2 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/trim_path_animation03.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2014 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. +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" > + + <objectAnimator + android:duration="6000" + android:propertyName="rotation" + android:valueFrom="0" + android:valueTo="360"/> + +</set>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation04.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation04.xml new file mode 100644 index 0000000..ff86668 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/trim_path_animation04.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2014 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. +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" > + + <objectAnimator + android:duration="9000" + android:propertyName="rotation" + android:valueFrom="0" + android:valueTo="360"/> + +</set>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml new file mode 100644 index 0000000..b8681b6 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml @@ -0,0 +1,36 @@ +<!-- + Copyright (C) 2014 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. +--> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/vector_drawable12" > + + <target + android:name="pie1" + android:animation="@anim/trim_path_animation01" /> + <target + android:name="v" + android:animation="@anim/trim_path_animation02" /> + + <target + android:name="rotationGroup" + android:animation="@anim/trim_path_animation03" /> + <target + android:name="rotationGroup3" + android:animation="@anim/trim_path_animation03" /> + <target + android:name="rotationGroupBlue" + android:animation="@anim/trim_path_animation03" /> + +</animated-vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml index 3042f6a..e28ec41 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml @@ -23,11 +23,15 @@ android:viewportHeight="600" android:viewportWidth="600" /> - <group> + <group + android:name="rotationGroup" + android:pivotX="300.0" + android:pivotY="300.0" + android:rotation="45.0" > <path android:name="pie1" - android:pathData="M300,70 a230,230 0 1,0 1,0 z" android:fill="#00000000" + android:pathData="M300,70 a230,230 0 1,0 1,0 z" android:stroke="#FF00FF00" android:strokeWidth="70" android:trimPathEnd=".75" @@ -36,7 +40,66 @@ <path android:name="v" android:fill="#FF00FF00" - android:pathData="M300,70 l 0,-70 70,70 -70,70z"/> + android:pathData="M300,70 l 0,-70 70,70 -70,70z" /> + + <group + android:name="translateToCenterGroup" + android:rotation="0.0" + android:translateX="200.0" + android:translateY="200.0" > + <path + android:name="twoLines" + android:pathData="@string/twoLinePathData" + android:stroke="#FFFF0000" + android:strokeWidth="20" /> + + <group + android:name="rotationGroup2" + android:pivotX="0.0" + android:pivotY="0.0" + android:rotation="-45.0" > + <path + android:name="twoLines1" + android:pathData="@string/twoLinePathData" + android:stroke="#FF00FF00" + android:strokeWidth="20" /> + + <group + android:name="translateGroupHalf" + android:translateX="65.0" + android:translateY="80.0" > + <group + android:name="rotationGroup3" + android:pivotX="-65.0" + android:pivotY="-80.0" + android:rotation="-45.0" > + <path + android:name="twoLines2" + android:fill="#FF00FF00" + android:pathData="@string/twoLinePathData" + android:stroke="#FF00FF00" + android:strokeWidth="20" /> + + <group + android:name="translateGroup" + android:translateX="65.0" + android:translateY="80.0" > + <group + android:name="rotationGroupBlue" + android:pivotX="-65.0" + android:pivotY="-80.0" + android:rotation="-45.0" > + <path + android:name="twoLines3" + android:pathData="@string/twoLinePathData" + android:stroke="#FF0000FF" + android:strokeWidth="20" /> + </group> + </group> + </group> + </group> + </group> + </group> </group> </vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java new file mode 100644 index 0000000..6e864fa --- /dev/null +++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014 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 com.android.test.dynamic; + +import android.app.Activity; +import android.graphics.drawable.AnimatedVectorDrawable; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; + +public class AnimatedVectorDrawableTest extends Activity { + private static final String LOGCAT = "VectorDrawableAnimationTest"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Button button = new Button(this); + button.setBackgroundResource(R.drawable.animation_vector_drawable01); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + AnimatedVectorDrawable frameAnimation = (AnimatedVectorDrawable) v.getBackground(); + frameAnimation.start(); + } + }); + + setContentView(button); + } +} diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableAnimation.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableAnimation.java index 99de037..93b06b6 100644 --- a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableAnimation.java +++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableAnimation.java @@ -14,6 +14,7 @@ package com.android.test.dynamic; +import android.animation.ValueAnimator; import android.app.Activity; import android.graphics.drawable.AnimationDrawable; import android.os.Bundle; @@ -27,7 +28,7 @@ public class VectorDrawableAnimation extends Activity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - Button button = new Button(this); + final Button button = new Button(this); button.setBackgroundResource(R.drawable.animation_drawable_vector); button.setOnClickListener(new View.OnClickListener() { |
