summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/animation/AnimatorInflater.java237
-rw-r--r--core/java/android/view/animation/AccelerateInterpolator.java30
-rw-r--r--core/java/android/view/animation/AnimationUtils.java98
-rw-r--r--core/java/android/view/animation/AnticipateInterpolator.java18
-rw-r--r--core/java/android/view/animation/AnticipateOvershootInterpolator.java14
-rw-r--r--core/java/android/view/animation/CycleInterpolator.java28
-rw-r--r--core/java/android/view/animation/DecelerateInterpolator.java32
-rw-r--r--core/java/android/view/animation/OvershootInterpolator.java18
-rw-r--r--core/java/android/view/animation/PathInterpolator.java41
-rw-r--r--core/res/res/values/attrs.xml25
-rw-r--r--graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java250
-rw-r--r--graphics/java/android/graphics/drawable/Drawable.java24
-rw-r--r--graphics/java/android/graphics/drawable/VectorDrawable.java205
-rw-r--r--tests/VectorDrawableTest/AndroidManifest.xml20
-rw-r--r--tests/VectorDrawableTest/res/anim/trim_path_animation01.xml35
-rw-r--r--tests/VectorDrawableTest/res/anim/trim_path_animation02.xml26
-rw-r--r--tests/VectorDrawableTest/res/anim/trim_path_animation03.xml26
-rw-r--r--tests/VectorDrawableTest/res/anim/trim_path_animation04.xml26
-rw-r--r--tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml36
-rw-r--r--tests/VectorDrawableTest/res/drawable/vector_drawable12.xml69
-rw-r--r--tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java42
-rw-r--r--tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableAnimation.java3
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() {