Add AnimatedVectorDrawable

Currently as a hidden class.
It can support many the animations now as far as ObjectAnimator and
hierarchical group can support.
And we don't have path morphing yet.

Also support the Animator / Interpolator inflation from Context and Resources.

Change-Id: I948bbdf7373ad291171eed0b497959dce8c2edf3
This commit is contained in:
ztenghui
2014-06-03 14:02:10 -07:00
parent 88b0078468
commit e5e92602a4
22 changed files with 1077 additions and 226 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 */

View File

@@ -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 */

View File

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

View File

@@ -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) {

View File

@@ -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" />
@@ -4854,6 +4854,25 @@
<attr name="strokeMiterLimit" format="float"/>
</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 -->
<!-- ========================== -->

View File

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

View File

@@ -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")) {

View File

@@ -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;
@@ -161,6 +167,11 @@ public class VectorDrawable extends Drawable {
canvas.restoreToCount(saveCount);
}
@Override
public int getAlpha() {
return mVectorState.mVPathRenderer.getRootAlpha();
}
@Override
public void setAlpha(int alpha) {
if (mVectorState.mVPathRenderer.getRootAlpha() != 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;
public String getName() {
return mName;
/* 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 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)) {

View File

@@ -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>
@@ -51,6 +51,15 @@
<category android:name="android.intent.category.LAUNCHER" />
</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" >
@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

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

View File

@@ -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() {