diff options
author | Alan Viverette <alanv@google.com> | 2014-04-07 23:55:29 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2014-04-07 23:55:29 +0000 |
commit | af22ce470112b8ee2ea7edf17b5d7c78e92d8ff7 (patch) | |
tree | 384863249c75f822e50f9af615c80ba77f623fc4 | |
parent | f7fbe099a80a6955f7c910dbae3c6fecfc0b151a (diff) | |
parent | 9453b7cfd4bbb35467bd7f947f850bd154982fce (diff) | |
download | frameworks_base-af22ce470112b8ee2ea7edf17b5d7c78e92d8ff7.zip frameworks_base-af22ce470112b8ee2ea7edf17b5d7c78e92d8ff7.tar.gz frameworks_base-af22ce470112b8ee2ea7edf17b5d7c78e92d8ff7.tar.bz2 |
Merge "Color theming for VectorDrawable, general clean up"
-rw-r--r-- | graphics/java/android/graphics/drawable/VectorDrawable.java | 403 |
1 files changed, 297 insertions, 106 deletions
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index 33683ab..d6f75ba 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -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) { + if (copy != null) { + mChangingConfigurations = copy.mChangingConfigurations; + mVAnimatedPath = new VAnimatedPath(copy.mVAnimatedPath); + mPadding = new Rect(copy.mPadding); + mIntrinsicHeight = copy.mIntrinsicHeight; + mIntrinsicWidth = copy.mIntrinsicWidth; + } } - public VectorDrawableState(VectorDrawableState copy){ - 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, null, null); } @Override - public Drawable newDrawable() { - return new VectorDrawable(this); + 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; |