Merge "Color theming for VectorDrawable, general clean up"

This commit is contained in:
Alan Viverette
2014-04-07 23:55:29 +00:00
committed by Android (Google) Code Review

View File

@@ -14,7 +14,6 @@
package android.graphics.drawable;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.res.Resources;
@@ -28,11 +27,7 @@ import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.location.Address;
import android.net.ParseException;
import android.sax.StartElementListener;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
@@ -47,7 +42,6 @@ import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -157,8 +151,8 @@ import java.util.HashSet;
* </dd>
*/
public class VectorDrawable extends Drawable {
private static final String LOGTAG = "VectorDrawable";
public static final int INFINITE = ValueAnimator.INFINITE;
private static final String LOGTAG = VectorDrawable.class.getSimpleName();
private static final String SHAPE_SIZE = "size";
private static final String SHAPE_VIEWPORT = "viewport";
private static final String SHAPE_GROUP = "group";
@@ -170,23 +164,32 @@ public class VectorDrawable extends Drawable {
private static final int LINECAP_BUTT = 0;
private static final int LINECAP_ROUND = 1;
private static final int LINECAP_SQUARE = 2;
private static final int LINEJOIN_MITER = 0;
private static final int LINEJOIN_ROUND = 1;
private static final int LINEJOIN_BEVEL = 2;
private static final int DEFAULT_DURATION = 1000;
private static final long DEFAULT_INFINITE_DURATION = 60 * 60 * 1000;
private VectorDrawableState mVectorState;
private int mAlpha = 0xFF;
public VectorDrawable() {
mVectorState = new VectorDrawableState();
mVectorState = new VectorDrawableState(null);
mVectorState.mBasicAnimator = ObjectAnimator.ofFloat(this, "AnimationFraction", 0, 1);
setDuration(DEFAULT_DURATION);
}
private VectorDrawable(VectorDrawableState state) {
private VectorDrawable(VectorDrawableState state, Resources res, Theme theme) {
mVectorState = new VectorDrawableState(state);
mVectorState.mBasicAnimator = ObjectAnimator.ofFloat(this, "AnimationFraction", 0, 1);
if (theme != null && canApplyTheme()) {
applyTheme(theme);
}
long duration = mVectorState.mVAnimatedPath.getTotalAnimationDuration();
if (duration == -1) { // if it set to infinite set to 1 hour
duration = DEFAULT_INFINITE_DURATION; // TODO define correct approach for infinite
@@ -197,6 +200,7 @@ public class VectorDrawable extends Drawable {
}
final static class VectorDrawableState extends ConstantState {
int[] mThemeAttrs;
int mChangingConfigurations;
ValueAnimator mBasicAnimator;
VAnimatedPath mVAnimatedPath = new VAnimatedPath();
@@ -204,20 +208,29 @@ public class VectorDrawable extends Drawable {
int mIntrinsicHeight;
int mIntrinsicWidth;
public VectorDrawableState(){
}
public VectorDrawableState(VectorDrawableState copy){
mChangingConfigurations = copy.mChangingConfigurations;
mVAnimatedPath = new VAnimatedPath(copy.mVAnimatedPath);
mPadding = new Rect(copy.mPadding);
mIntrinsicHeight = copy.mIntrinsicHeight;
mIntrinsicWidth = copy.mIntrinsicWidth;
public VectorDrawableState(VectorDrawableState copy) {
if (copy != null) {
mChangingConfigurations = copy.mChangingConfigurations;
mVAnimatedPath = new VAnimatedPath(copy.mVAnimatedPath);
mPadding = new Rect(copy.mPadding);
mIntrinsicHeight = copy.mIntrinsicHeight;
mIntrinsicWidth = copy.mIntrinsicWidth;
}
}
@Override
public Drawable newDrawable() {
return new VectorDrawable(this);
return new VectorDrawable(this, null, null);
}
@Override
public Drawable newDrawable(Resources res) {
return new VectorDrawable(this, res, null);
}
@Override
public Drawable newDrawable(Resources res, Theme theme) {
return new VectorDrawable(this, res, theme);
}
@Override
@@ -459,29 +472,49 @@ public class VectorDrawable extends Drawable {
@Override
public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
throws XmlPullParserException, IOException {
setAnimatedPath(inflateInternal(res, parser, attrs));
final VAnimatedPath p = inflateInternal(res, parser, attrs, theme);
setAnimatedPath(p);
}
private VAnimatedPath inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs)
throws XmlPullParserException, IOException {
@Override
public boolean canApplyTheme() {
return super.canApplyTheme() || mVectorState != null && mVectorState.canApplyTheme();
}
@Override
public void applyTheme(Theme t) {
super.applyTheme(t);
final VectorDrawableState state = mVectorState;
final VAnimatedPath path = state.mVAnimatedPath;
if (path != null && path.canApplyTheme()) {
path.applyTheme(t);
}
}
private VAnimatedPath inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
Theme theme) throws XmlPullParserException, IOException {
final VAnimatedPath animatedPath = new VAnimatedPath();
boolean noSizeTag = true;
boolean noViewportTag = true;
boolean noGroupTag = true;
boolean noPathTag = true;
final VAnimatedPath animatedPath = new VAnimatedPath();
VectorDrawable.VGroup currentGroup = null;
VGroup currentGroup = null;
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
String tagName = parser.getName();
final String tagName = parser.getName();
if (SHAPE_PATH.equals(tagName)) {
VectorDrawable.VPath p = new VPath(res, attrs);
currentGroup.add(p);
final VPath path = new VPath();
path.inflate(res, attrs, theme);
currentGroup.add(path);
noPathTag = false;
} else if (SHAPE_ANIMATION.equals(tagName)) {
VectorDrawable.VAnimation anim =
new VAnimation(res, attrs, animatedPath.mGroupList);
final VAnimation anim = new VAnimation();
anim.inflate(animatedPath.mGroupList, res, attrs, theme);
animatedPath.addAnimation(anim);
} else if (SHAPE_SIZE.equals(tagName)) {
animatedPath.parseSize(res, attrs);
@@ -490,17 +523,17 @@ public class VectorDrawable extends Drawable {
animatedPath.parseViewport(res, attrs);
noViewportTag = false;
} else if (SHAPE_GROUP.equals(tagName)) {
currentGroup = new VectorDrawable.VGroup();
currentGroup = new VGroup();
animatedPath.mGroupList.add(currentGroup);
noGroupTag = false;
} else if (SHAPE_VECTOR.equals(tagName)) {
TypedArray a = res.obtainAttributes(attrs, R.styleable.VectorDrawable);
final TypedArray a = res.obtainAttributes(attrs, R.styleable.VectorDrawable);
animatedPath.setTrigger(a.getInteger(R.styleable.VectorDrawable_trigger, 0));
// Parsing the version information.
// Right now, we only support version "1".
// If the xml didn't specify the version number, the default version is "1".
int versionCode = a.getInt(R.styleable.VectorDrawable_versionCode, 1);
final int versionCode = a.getInt(R.styleable.VectorDrawable_versionCode, 1);
if (versionCode != 1) {
throw new IllegalArgumentException(
"So far, VectorDrawable only support version 1");
@@ -509,33 +542,41 @@ public class VectorDrawable extends Drawable {
a.recycle();
}
}
eventType = parser.next();
}
if (noSizeTag || noViewportTag || noGroupTag || noPathTag) {
StringBuffer tag = new StringBuffer();
final StringBuffer tag = new StringBuffer();
if (noSizeTag) {
tag.append("size");
tag.append(SHAPE_SIZE);
}
if (noViewportTag){
if (tag.length()>0) {
tag.append(" & ");
}
tag.append("size");
tag.append(SHAPE_SIZE);
}
if (noGroupTag){
if (tag.length()>0) {
tag.append(" & ");
}
tag.append("group");
tag.append(SHAPE_GROUP);
}
if (noPathTag){
if (tag.length()>0) {
tag.append(" or ");
}
tag.append("path");
tag.append(SHAPE_PATH);
}
throw new XmlPullParserException("no "+tag+" defined");
throw new XmlPullParserException("no " + tag + " defined");
}
// post parse cleanup
animatedPath.parseFinish();
return animatedPath;
@@ -543,16 +584,18 @@ public class VectorDrawable extends Drawable {
private void setAnimatedPath(VAnimatedPath animatedPath) {
mVectorState.mVAnimatedPath = animatedPath;
setIntrinsicWidth((int) mVectorState.mVAnimatedPath.mBaseWidth);
setIntrinsicHeight((int) mVectorState.mVAnimatedPath.mBaseHeight);
long duration = mVectorState.mVAnimatedPath.getTotalAnimationDuration();
if (duration == -1) { // if it set to infinite set to 1 hour
duration = DEFAULT_INFINITE_DURATION; // TODO define correct approach for infinite
mVectorState.mBasicAnimator.setFloatValues(0, duration / 1000);
mVectorState.mBasicAnimator.setInterpolator(new LinearInterpolator());
}
setDuration(duration);
setDuration(duration);
setAnimationFraction(0);
}
@@ -570,8 +613,6 @@ public class VectorDrawable extends Drawable {
}
private static class VAnimatedPath {
private static final String LOGTAG = "VAnimatedPath";
private ArrayList<VAnimation> mCurrentAnimList = null;
private VPath[] mCurrentPaths;
private float mAnimationValue = 0; // value goes from 0 to 1
@@ -585,7 +626,9 @@ public class VectorDrawable extends Drawable {
private int[] mCurrentState = new int[0];
private int mTrigger;
private boolean mTriggerState;
ArrayList<VGroup> mGroupList = new ArrayList<VGroup>();
final ArrayList<VGroup> mGroupList = new ArrayList<VGroup>();
float mBaseWidth = 1;
float mBaseHeight = 1;
float mViewportWidth;
@@ -594,10 +637,11 @@ public class VectorDrawable extends Drawable {
public VAnimatedPath() {
setup();
}
public VAnimatedPath(VAnimatedPath copy) {
setup();
mCurrentAnimList = new ArrayList<VAnimation>(copy.mCurrentAnimList);
mGroupList = new ArrayList<VGroup>(copy.mGroupList);
mGroupList.addAll(copy.mGroupList);
if (copy.mCurrentPaths != null) {
mCurrentPaths = new VPath[copy.mCurrentPaths.length];
for (int i = 0; i < mCurrentPaths.length; i++) {
@@ -615,8 +659,53 @@ public class VectorDrawable extends Drawable {
mCurrentState = new int[0];
}
public boolean canApplyTheme() {
final ArrayList<VGroup> groups = mGroupList;
for (int i = groups.size() - 1; i >= 0; i--) {
final ArrayList<VPath> paths = groups.get(i).mVGList;
for (int j = paths.size() - 1; j >= 0; j--) {
final VPath path = paths.get(j);
if (path.canApplyTheme()) {
return true;
}
}
}
final ArrayList<VAnimation> anims = mCurrentAnimList;
for (int i = anims.size() - 1; i >= 0; i--) {
final VAnimation anim = anims.get(i);
if (anim.canApplyTheme()) {
return true;
}
}
return false;
}
public void applyTheme(Theme t) {
final ArrayList<VGroup> groups = mGroupList;
for (int i = groups.size() - 1; i >= 0; i--) {
final ArrayList<VPath> paths = groups.get(i).mVGList;
for (int j = paths.size() - 1; j >= 0; j--) {
final VPath path = paths.get(j);
if (path.canApplyTheme()) {
path.applyTheme(t);
}
}
}
final ArrayList<VAnimation> anims = mCurrentAnimList;
for (int i = anims.size() - 1; i >= 0; i--) {
final VAnimation anim = anims.get(i);
if (anim.canApplyTheme()) {
anim.applyTheme(t);
}
}
}
public void setTrigger(int trigger){
int []lut = { 0,
final int [] lut = {
0,
R.attr.state_pressed,
R.attr.state_focused,
R.attr.state_hovered,
@@ -626,6 +715,7 @@ public class VectorDrawable extends Drawable {
R.attr.state_activated,
R.attr.state_focused
};
mTrigger = lut[trigger];
}
@@ -663,23 +753,27 @@ public class VectorDrawable extends Drawable {
* @return true if you need to keep repeating
*/
public boolean setAnimationFraction(float value) {
int len = mCurrentPaths.length;
getTotalAnimationDuration();
long animationTime = (long) (value * mTotalDuration);
final int len = mCurrentPaths.length;
for (int i = 0; i < len; i++) {
VPath path = mCurrentPaths[i];
animationTime =
(long) ((mTotalDuration == -1) ? value * 1000 : mTotalDuration * value);
int size = mCurrentAnimList.size();
final VPath path = mCurrentPaths[i];
final int size = mCurrentAnimList.size();
for (int j = 0; j < size; j++) {
VAnimation vAnimation = mCurrentAnimList.get(j);
final VAnimation vAnimation = mCurrentAnimList.get(j);
if (vAnimation.doesAdjustPath(path)) {
mCurrentPaths[i] = vAnimation.getPathAtTime(animationTime, path);
}
}
}
this.mAnimationValue = value;
mAnimationValue = value;
if (mTotalDuration == -1) {
return true;
} else {
@@ -688,16 +782,15 @@ public class VectorDrawable extends Drawable {
}
public void draw(Canvas canvas) {
int w = canvas.getWidth();
int h = canvas.getHeight();
float scale = w / mViewportWidth;
scale = Math.min(h / mViewportHeight, scale);
if (mCurrentPaths == null) {
Log.e(LOGTAG,"mCurrentPaths == null");
return;
}
// TODO: This should probably use getBounds().
final int w = canvas.getWidth();
final int h = canvas.getHeight();
for (int i = 0; i < mCurrentPaths.length; i++) {
if (mCurrentPaths[i] != null && mCurrentPaths[i].isVisible(mCurrentState)) {
drawPath(mCurrentPaths[i], canvas, w, h);
@@ -706,8 +799,7 @@ public class VectorDrawable extends Drawable {
}
private void drawPath(VPath vPath, Canvas canvas, int w, int h) {
float scale = w / mViewportWidth;
scale = Math.min(h / mViewportHeight, scale);
final float scale = Math.min(h / mViewportHeight, w / mViewportWidth);
vPath.toPath(mPath);
Path path = mPath;
@@ -746,12 +838,14 @@ public class VectorDrawable extends Drawable {
if (vPath.mClip) {
canvas.clipPath(mRenderPath, Region.Op.REPLACE);
}
if (vPath.mFillColor != 0) {
mFillPaint.setColor(vPath.mFillColor);
int alpha = 0xFF & (vPath.mFillColor >> 24);
mFillPaint.setAlpha(alpha);
canvas.drawPath(mRenderPath, mFillPaint);
}
if (vPath.mStrokeColor != 0) {
if (vPath.mStrokelineJoin != null) {
mStrokePaint.setStrokeJoin(vPath.mStrokelineJoin);
@@ -773,7 +867,7 @@ public class VectorDrawable extends Drawable {
* TODO: improve memory use & performance or move to C++
*/
public void parseFinish() {
HashMap<String, VAnimation> newAnimations = new HashMap<String, VAnimation>();
final HashMap<String, VAnimation> newAnimations = new HashMap<String, VAnimation>();
for (VGroup group : mGroupList) {
for (VPath vPath : group.getPaths()) {
if (!vPath.mAnimated) {
@@ -784,16 +878,19 @@ public class VectorDrawable extends Drawable {
} else {
ap = newAnimations.get(vPath.getID());
}
ap.addPath(vPath);
vPath.mAnimated = true;
}
}
}
if (mCurrentAnimList == null) {
mCurrentAnimList = new ArrayList<VectorDrawable.VAnimation>();
}
mCurrentAnimList.addAll(newAnimations.values());
Collection<VPath> paths = mGroupList.get(0).getPaths();
final Collection<VPath> paths = mGroupList.get(0).getPaths();
mCurrentPaths = paths.toArray(new VPath[paths.size()]);
for (int i = 0; i < mCurrentPaths.length; i++) {
mCurrentPaths[i] = new VPath(mCurrentPaths[i]);
@@ -854,40 +951,41 @@ public class VectorDrawable extends Drawable {
}
private static class VAnimation {
private static final String LOGTAG = "VAnimation";
private final static int DIRECTION_FORWARD = 0;
private final static int DIRECTION_IN_AND_OUT = 1;
private VPath[] mPaths = new VPath[0];
public enum Style {
INTERPOLATE, CROSSFADE, WIPE
}
Interpolator mAnimInterpolator = new AccelerateDecelerateInterpolator();
private int[] mThemeAttrs;
private Style mStyle;
private int mLimitProperty = 0;
private long[] mDuration = {DEFAULT_DURATION};
private long mStartOffset;
private long mRepeat = 1;
private HashSet<String>mSeqMap = new HashSet<String>();
private HashSet<String> mSeqMap = new HashSet<String>();
private long mWipeDirection;
private int mMode = 0; // forward = 0 inAndOut = 1;
private int mInterpolatorType;
private String mId;
private final static int DIRECTION_FORWARD = 0;
private final static int DIRECTION_IN_AND_OUT = 1;
public VAnimation() {
// Empty constructor.
}
public boolean doesAdjustPath(VPath path) {
return mSeqMap.contains(path.getID());
}
public VAnimation(Resources r, AttributeSet attrs, ArrayList<VGroup> groups)
public void inflate(ArrayList<VGroup> groups, Resources r, AttributeSet attrs, Theme theme)
throws XmlPullParserException {
String value;
String[] sp;
int name;
TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableAnimation);
final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableAnimation);
mThemeAttrs = a.extractThemeAttrs();
value = a.getString(R.styleable.VectorDrawableAnimation_sequence);
if (value != null) {
@@ -910,28 +1008,42 @@ public class VectorDrawable extends Drawable {
if (value != null) {
long totalDuration = 0;
sp = value.split(",");
long[] dur = new long[sp.length];
final long[] dur = new long[sp.length];
for (int j = 0; j < dur.length; j++) {
dur[j] = Long.parseLong(sp[j]);
totalDuration += dur[j];
}
if (totalDuration == 0){
throw new XmlPullParserException(a.getPositionDescription()+
"total duration must not be zero");
}
setDuration(dur);
}
setRepeat(a.getInt(R.styleable.VectorDrawableAnimation_repeatCount, 1));
setStartOffset(a.getInt(R.styleable.VectorDrawableAnimation_startDelay, 0));
setMode(a.getInt(R.styleable.VectorDrawableAnimation_repeatStyle, 0));
fixMissingParameters();
a.recycle();
}
public boolean canApplyTheme() {
return mThemeAttrs != null;
}
public void applyTheme(Theme t) {
// TODO: Apply theme.
}
public boolean doesAdjustPath(VPath path) {
return mSeqMap.contains(path.getID());
}
public String getId() {
if (mId == null) {
mId = mPaths[0].getID();
@@ -1031,7 +1143,7 @@ public class VectorDrawable extends Drawable {
}
public void setPaths(VPath[] paths) {
this.mPaths = paths;
mPaths = paths;
}
public void addPath(VPath path) {
@@ -1049,7 +1161,7 @@ public class VectorDrawable extends Drawable {
}
public void interpolate(VPath p1, VPath p2, float time, VPath dest) {
dest.interpolate(time, p1, p2, dest, mLimitProperty);
VPath.interpolate(time, p1, p2, dest, mLimitProperty);
}
public VPath getPathAtTime(long milliseconds, VPath dest) {
@@ -1150,8 +1262,8 @@ public class VectorDrawable extends Drawable {
}
private static class VGroup {
private HashMap<String, VPath> mVGPathMap = new HashMap<String, VPath>();
private ArrayList<VPath> mVGList = new ArrayList<VPath>();
private final HashMap<String, VPath> mVGPathMap = new HashMap<String, VPath>();
private final ArrayList<VPath> mVGList = new ArrayList<VPath>();
public void add(VPath path) {
String id = path.getID();
@@ -1183,34 +1295,52 @@ public class VectorDrawable extends Drawable {
private static final int LIMIT_TRIM_PATH_START = 3;
private static final int LIMIT_TRIM_PATH_OFFSET = 5;
private static final int LIMIT_TRIM_PATH_END = 4;
private static final int STATE_UNDEFINED=0;
private static final int STATE_TRUE=1;
private static final int STATE_FALSE=2;
private static final int MAX_STATES = 10;
private VNode[] mNode = null;
private String mId;
private int[] mThemeAttrs;
int mStrokeColor = 0;
float mStrokeWidth = 0;
float mStrokeOpacity = Float.NaN;
int mFillColor = 0;
int mFillRule;
float mFillOpacity = Float.NaN;
float mRotate = 0;
float mPivotX = 0;
float mPivotY = 0;
float mTrimPathStart = 0;
float mTrimPathEnd = 1;
float mTrimPathOffset = 0;
boolean mAnimated = false;
boolean mClip = false;
public Paint.Cap mStrokelineCap = null;
public Paint.Join mStrokelineJoin = null;
Paint.Cap mStrokelineCap = null;
Paint.Join mStrokelineJoin = null;
float mStrokeMiterlimit = 4;
private VNode[] mNode = null;
private String mId;
private int[] mCheckState = new int[MAX_STATES];
private boolean[] mCheckValue = new boolean[MAX_STATES];
private int mNumberOfStates = 0;
private int mNumberOfTrue = 0;
public VPath() {
// Empty constructor.
}
public VPath(VPath p) {
copyFrom(p);
}
public void addStateFilter(int state, boolean condition) {
int k = 0;
while (k < mNumberOfStates) {
@@ -1228,7 +1358,7 @@ public class VectorDrawable extends Drawable {
}
}
int getState(int state){
private int getState(int state){
for (int i = 0; i < mNumberOfStates; i++) {
if (mCheckState[mNumberOfStates] == state){
return (mCheckValue[i])?STATE_TRUE:STATE_FALSE;
@@ -1250,34 +1380,33 @@ public class VectorDrawable extends Drawable {
}
}
public VPath() {
mId = this.toString(); // to ensure paths have unique names
}
public VPath(VPath p) {
copyFrom(p);
}
public String getID(){
return mId;
}
public VPath(Resources r, AttributeSet attrs) {
TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawablePath);
public void inflate(Resources r, AttributeSet attrs, Theme theme) {
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawablePath);
final int[] themeAttrs = a.extractThemeAttrs();
mThemeAttrs = themeAttrs;
mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, false);
mId = a.getString(R.styleable.VectorDrawablePath_name);
mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData));
mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, 0);
mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, Float.NaN);
if (!Float.isNaN(mFillOpacity)) {
mFillColor &= 0x00FFFFFF;
mFillColor |= ((int) (0xFF * mFillOpacity)) << 24;
if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fill] == 0) {
mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, 0);
}
if (themeAttrs == null
|| themeAttrs[R.styleable.VectorDrawablePath_fillOpacity] == 0) {
mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, Float.NaN);
}
mRotate = a.getFloat(R.styleable.VectorDrawablePath_rotation, 0);
mPivotX = a.getFloat(R.styleable.VectorDrawablePath_pivotX, 0);
mPivotY = a.getFloat(R.styleable.VectorDrawablePath_pivotY, 0);
int lineCap = a.getInt(R.styleable.VectorDrawablePath_strokeLineCap, 0);
final int lineCap = a.getInt(R.styleable.VectorDrawablePath_strokeLineCap, 0);
switch (lineCap) {
case LINECAP_BUTT:
mStrokelineCap = Paint.Cap.BUTT;
@@ -1289,7 +1418,8 @@ public class VectorDrawable extends Drawable {
mStrokelineCap = Paint.Cap.SQUARE;
break;
}
int lineJoin = a.getInt(R.styleable.VectorDrawablePath_strokeLineJoin, 0);
final int lineJoin = a.getInt(R.styleable.VectorDrawablePath_strokeLineJoin, 0);
switch (lineJoin) {
case LINEJOIN_MITER:
mStrokelineJoin = Paint.Join.MITER;
@@ -1301,19 +1431,27 @@ public class VectorDrawable extends Drawable {
mStrokelineJoin = Paint.Join.BEVEL;
break;
}
mStrokeMiterlimit = a.getFloat(R.styleable.VectorDrawablePath_strokeMiterLimit,
mStrokeMiterlimit);
mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor);
mStrokeOpacity = a.getFloat(R.styleable.VectorDrawablePath_strokeOpacity, Float.NaN);
if (!Float.isNaN(mStrokeOpacity)) {
mStrokeColor &= 0x00FFFFFF;
mStrokeColor |= ((int) (0xFF * mStrokeOpacity)) << 24;
if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_stroke] == 0) {
mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor);
}
if (themeAttrs == null
|| themeAttrs[R.styleable.VectorDrawablePath_strokeOpacity] == 0) {
mStrokeOpacity = a.getFloat(
R.styleable.VectorDrawablePath_strokeOpacity, Float.NaN);
}
mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, 0);
mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, 1);
mTrimPathOffset = a.getFloat(R.styleable.VectorDrawablePath_trimPathOffset, 0);
mTrimPathStart = a.getFloat(R.styleable.VectorDrawablePath_trimPathStart, 0);
int[] states = {R.styleable.VectorDrawablePath_state_activated,
final int[] states = {
R.styleable.VectorDrawablePath_state_activated,
R.styleable.VectorDrawablePath_state_checkable,
R.styleable.VectorDrawablePath_state_checked,
R.styleable.VectorDrawablePath_state_enabled,
@@ -1321,15 +1459,66 @@ public class VectorDrawable extends Drawable {
R.styleable.VectorDrawablePath_state_hovered,
R.styleable.VectorDrawablePath_state_pressed,
R.styleable.VectorDrawablePath_state_selected,
R.styleable.VectorDrawablePath_state_window_focused};
for (int state : states) {
R.styleable.VectorDrawablePath_state_window_focused
};
final int N = states.length;
for (int i = 0; i < N; i++) {
final int state = states[i];
if (a.hasValue(state)) {
addStateFilter(state, a.getBoolean(state, false));
}
}
updateColorAlphas();
a.recycle();
}
public boolean canApplyTheme() {
return mThemeAttrs != null;
}
public void applyTheme(Theme t) {
if (mThemeAttrs == null) {
return;
}
final TypedArray a = t.resolveAttributes(
mThemeAttrs, R.styleable.VectorDrawablePath, 0, 0);
if (a.hasValue(R.styleable.VectorDrawablePath_fill)) {
mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, 0);
}
if (a.hasValue(R.styleable.VectorDrawablePath_fillOpacity)) {
mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, Float.NaN);
}
if (a.hasValue(R.styleable.VectorDrawablePath_stroke)) {
mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor);
}
if (a.hasValue(R.styleable.VectorDrawablePath_strokeOpacity)) {
mStrokeOpacity = a.getFloat(
R.styleable.VectorDrawablePath_strokeOpacity, Float.NaN);
}
updateColorAlphas();
}
private void updateColorAlphas() {
if (!Float.isNaN(mFillOpacity)) {
mFillColor &= 0x00FFFFFF;
mFillColor |= ((int) (0xFF * mFillOpacity)) << 24;
}
if (!Float.isNaN(mStrokeOpacity)) {
mStrokeColor &= 0x00FFFFFF;
mStrokeColor |= ((int) (0xFF * mStrokeOpacity)) << 24;
}
}
private static int nextStart(String s, int end) {
char c;
@@ -1564,9 +1753,11 @@ public class VectorDrawable extends Drawable {
}
private static class VNode {
private static float[] current = new float[4];
char type;
float[] params;
private static float[] current = new float[4];
public VNode(char type, float[] params) {
this.type = type;
this.params = params;