VectorDrawable.java revision 9cd14fc710cf81cc6d1c47d599abe349d3aa87dc
1e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka/*
2e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * Copyright (C) 2014 The Android Open Source Project
3e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka *
4e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * in compliance with the License. You may obtain a copy of the License at
6e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka *
7e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * http://www.apache.org/licenses/LICENSE-2.0
8e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka *
9e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * Unless required by applicable law or agreed to in writing, software distributed under the License
10e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * or implied. See the License for the specific language governing permissions and limitations under
12e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * the License.
13e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka */
14e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
15e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkapackage android.graphics.drawable;
16e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
17e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.content.res.ColorStateList;
18e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.content.res.Resources;
19e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.content.res.Resources.Theme;
20e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.content.res.TypedArray;
21e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Canvas;
22e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Color;
23e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.ColorFilter;
24e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Matrix;
25e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Paint;
26e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Path;
27e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.PathMeasure;
28e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.PixelFormat;
29e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.PorterDuffColorFilter;
30e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Rect;
31e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Region;
32e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.PorterDuff.Mode;
33e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.util.ArrayMap;
34e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.util.AttributeSet;
35e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.util.Log;
36e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.util.PathParser;
37e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.util.Xml;
38e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
39e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport com.android.internal.R;
40e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
41e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport org.xmlpull.v1.XmlPullParser;
42e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport org.xmlpull.v1.XmlPullParserException;
43e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport org.xmlpull.v1.XmlPullParserFactory;
44e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
45e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport java.io.IOException;
46e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport java.util.ArrayList;
47e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport java.util.Arrays;
48e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport java.util.Stack;
49e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
50e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka/**
51e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * This lets you create a drawable based on an XML vector graphic It can be
52e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * defined in an XML file with the <code>&lt;vector></code> element.
53e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <p/>
54e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * The vector drawable has the following elements:
55e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <p/>
56e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dl>
57e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dt><code>&lt;vector></code></dt>
58e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dd>Used to defined a vector drawable</dd>
59e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dt><code>&lt;size></code></dt>
60e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dd>Used to defined the intrinsic Width Height size of the drawable using
61e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <code>android:width</code> and <code>android:height</code></dd>
62e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dt><code>&lt;viewport></code></dt>
63e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dd>Used to defined the size of the virtual canvas the paths are drawn on.
64e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * The size is defined using the attributes <code>android:viewportHeight</code>
65e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <code>android:viewportWidth</code></dd>
66e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dt><code>&lt;group></code></dt>
67e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dd>Defines a group of paths or subgroups, plus transformation information.
68e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * The transformations are defined in the same coordinates as the viewport.
69e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * And the transformations are applied in the order of scale, rotate then translate. </dd>
70e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dt><code>android:rotation</code>
71e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dd>The degrees of rotation of the group.</dd></dt>
72e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dt><code>android:pivotX</code>
73e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dd>The X coordinate of the pivot for the scale and rotation of the group</dd></dt>
74e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dt><code>android:pivotY</code>
75e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dd>The Y coordinate of the pivot for the scale and rotation of the group</dd></dt>
76e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dt><code>android:scaleX</code>
77e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dd>The amount of scale on the X Coordinate</dd></dt>
78e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dt><code>android:scaleY</code>
79e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dd>The amount of scale on the Y coordinate</dd></dt>
80e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dt><code>android:translateX</code>
81e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dd>The amount of translation on the X coordinate</dd></dt>
82e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dt><code>android:translateY</code>
83e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dd>The amount of translation on the Y coordinate</dd></dt>
84e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dt><code>&lt;path></code></dt>
85e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dd>Defines paths to be drawn.
86e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dl>
87e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dt><code>android:name</code>
88e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dd>Defines the name of the path.</dd></dt>
89e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dt><code>android:pathData</code>
90e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dd>Defines path string. This is using exactly same format as "d" attribute
91e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * in the SVG's path data</dd></dt>
92e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dt><code>android:fill</code>
93e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dd>Defines the color to fill the path (none if not present).</dd></dt>
94e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dt><code>android:stroke</code>
95e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dd>Defines the color to draw the path outline (none if not present).</dd>
96e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * </dt>
97e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dt><code>android:strokeWidth</code>
98e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dd>The width a path stroke</dd></dt>
99e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dt><code>android:strokeOpacity</code>
100e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dd>The opacity of a path stroke</dd></dt>
101e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dt><code>android:fillOpacity</code>
102e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dd>The opacity to fill the path with</dd></dt>
103e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dt><code>android:trimPathStart</code>
104e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dd>The fraction of the path to trim from the start from 0 to 1</dd></dt>
105e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dt><code>android:trimPathEnd</code>
106e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dd>The fraction of the path to trim from the end from 0 to 1</dd></dt>
107e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dt><code>android:trimPathOffset</code>
108e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dd>Shift trim region (allows showed region to include the start and end)
109e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * from 0 to 1</dd></dt>
110e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dt><code>android:clipToPath</code>
111e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dd>Path will set the clip path</dd></dt>
112e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dt><code>android:strokeLineCap</code>
113e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dd>Sets the linecap for a stroked path: butt, round, square</dd></dt>
114e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dt><code>android:strokeLineJoin</code>
115e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dd>Sets the lineJoin for a stroked path: miter,round,bevel</dd></dt>
116e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dt><code>android:strokeMiterLimit</code>
117e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * <dd>Sets the Miter limit for a stroked path</dd></dt>
118e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * </dl>
119e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * </dd>
120e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka */
121e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkapublic class VectorDrawable extends Drawable {
122e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static final String LOGTAG = VectorDrawable.class.getSimpleName();
123e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
124e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static final String SHAPE_SIZE = "size";
125e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static final String SHAPE_VIEWPORT = "viewport";
126e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static final String SHAPE_GROUP = "group";
127e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static final String SHAPE_PATH = "path";
128e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static final String SHAPE_VECTOR = "vector";
129e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
130e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static final int LINECAP_BUTT = 0;
131e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static final int LINECAP_ROUND = 1;
132e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static final int LINECAP_SQUARE = 2;
133e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
134e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static final int LINEJOIN_MITER = 0;
135e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static final int LINEJOIN_ROUND = 1;
136e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static final int LINEJOIN_BEVEL = 2;
137e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
138e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static final boolean DBG_VECTOR_DRAWABLE = false;
139e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
140e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private final VectorDrawableState mVectorState;
141e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
142e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<String, Object>();
143e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
144e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private PorterDuffColorFilter mTintFilter;
145e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
146e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public VectorDrawable() {
147e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        mVectorState = new VectorDrawableState(null);
148e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
149e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
150e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private VectorDrawable(VectorDrawableState state, Resources res, Theme theme) {
151e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (theme != null && state.canApplyTheme()) {
152e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            // If we need to apply a theme, implicitly mutate.
153e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mVectorState = new VectorDrawableState(state);
154e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            applyTheme(theme);
155e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } else {
156e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mVectorState = state;
157e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
158e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
159e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
160e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        mVectorState.mVPathRenderer.setColorFilter(mTintFilter);
161e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
162e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
163e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    Object getTargetByName(String name) {
164e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return mVGTargetsMap.get(name);
165e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
166e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
167e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @Override
168e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public ConstantState getConstantState() {
169e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return mVectorState;
170e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
171e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
172e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @Override
173e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public void draw(Canvas canvas) {
174e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final int saveCount = canvas.save();
175e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final Rect bounds = getBounds();
176e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        canvas.translate(bounds.left, bounds.top);
177e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        mVectorState.mVPathRenderer.draw(canvas, bounds.width(), bounds.height());
178e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        canvas.restoreToCount(saveCount);
179e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
180e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
181e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @Override
182e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public int getAlpha() {
183e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return mVectorState.mVPathRenderer.getRootAlpha();
184e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
185e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
186e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @Override
187e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public void setAlpha(int alpha) {
188e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (mVectorState.mVPathRenderer.getRootAlpha() != alpha) {
189e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mVectorState.mVPathRenderer.setRootAlpha(alpha);
190e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            invalidateSelf();
191e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
192e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
193e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
194e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @Override
195e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public void setColorFilter(ColorFilter colorFilter) {
196e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final VectorDrawableState state = mVectorState;
197e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (colorFilter != null) {
198e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            // Color filter overrides tint.
199e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mTintFilter = null;
200e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } else if (state.mTint != null && state.mTintMode != null) {
201e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            // Restore the tint filter, if we need one.
202e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            final int color = state.mTint.getColorForState(getState(), Color.TRANSPARENT);
203e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
204e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            colorFilter = mTintFilter;
205e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
206e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
207e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        state.mVPathRenderer.setColorFilter(colorFilter);
208e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        invalidateSelf();
209e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
210e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
211e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @Override
212e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public void setTint(ColorStateList tint, Mode tintMode) {
213e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final VectorDrawableState state = mVectorState;
214e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (state.mTint != tint || state.mTintMode != tintMode) {
215e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            state.mTint = tint;
216e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            state.mTintMode = tintMode;
217e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
218e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mTintFilter = updateTintFilter(mTintFilter, tint, tintMode);
219e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mVectorState.mVPathRenderer.setColorFilter(mTintFilter);
220e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            invalidateSelf();
221e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
222e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
223e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
224e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @Override
225e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected boolean onStateChange(int[] stateSet) {
226e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final VectorDrawableState state = mVectorState;
227e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (state.mTint != null && state.mTintMode != null) {
228e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
229e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mVectorState.mVPathRenderer.setColorFilter(mTintFilter);
230e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return true;
231e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
232e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return false;
233e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
234e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
235e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @Override
236e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public int getOpacity() {
237e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return PixelFormat.TRANSLUCENT;
238e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
239e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
240e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    /**
241e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * Sets padding for this shape, defined by a Rect object. Define the padding
242e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * in the Rect object as: left, top, right, bottom.
243e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     */
244e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public void setPadding(Rect padding) {
245e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        setPadding(padding.left, padding.top, padding.right, padding.bottom);
246e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
247e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
248e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    /**
249e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * Sets padding for the shape.
250e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     *
251e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * @param left padding for the left side (in pixels)
252e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * @param top padding for the top (in pixels)
253e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * @param right padding for the right side (in pixels)
254e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * @param bottom padding for the bottom (in pixels)
255e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     */
256e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public void setPadding(int left, int top, int right, int bottom) {
257e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if ((left | top | right | bottom) == 0) {
258e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mVectorState.mPadding = null;
259e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } else {
260e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (mVectorState.mPadding == null) {
261e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mVectorState.mPadding = new Rect();
262e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
263e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mVectorState.mPadding.set(left, top, right, bottom);
264e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
265e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        invalidateSelf();
266e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
267e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
268e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @Override
269e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public int getIntrinsicWidth() {
270e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return (int) mVectorState.mVPathRenderer.mBaseWidth;
271e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
272e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
273e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @Override
274e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public int getIntrinsicHeight() {
275e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return (int) mVectorState.mVPathRenderer.mBaseHeight;
276e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
277e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
278e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @Override
279e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public boolean getPadding(Rect padding) {
280e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (mVectorState.mPadding != null) {
281e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            padding.set(mVectorState.mPadding);
282e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return true;
283e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } else {
284e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return super.getPadding(padding);
285e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
286e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
287e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
288e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @Override
289e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public boolean canApplyTheme() {
290e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return super.canApplyTheme() || mVectorState != null && mVectorState.canApplyTheme();
291e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
292e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
293e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @Override
294e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public void applyTheme(Theme t) {
295e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        super.applyTheme(t);
296e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
297e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final VectorDrawableState state = mVectorState;
298e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final VPathRenderer path = state.mVPathRenderer;
299e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (path != null && path.canApplyTheme()) {
300e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            path.applyTheme(t);
301e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
302e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
303e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
304e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    /** @hide */
305e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public static VectorDrawable create(Resources resources, int rid) {
306e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        try {
307e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            final XmlPullParser xpp = resources.getXml(rid);
308e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            final AttributeSet attrs = Xml.asAttributeSet(xpp);
309e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            final XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
310e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            factory.setNamespaceAware(true);
311e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
312e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            final VectorDrawable drawable = new VectorDrawable();
313e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            drawable.inflate(resources, xpp, attrs);
314e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
315e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return drawable;
316e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } catch (XmlPullParserException e) {
317e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Log.e(LOGTAG, "parser error", e);
318e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } catch (IOException e) {
319e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Log.e(LOGTAG, "parser error", e);
320e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
321e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return null;
322e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
323e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
324e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static int applyAlpha(int color, float alpha) {
325e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int alphaBytes = Color.alpha(color);
326e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        color &= 0x00FFFFFF;
327e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        color |= ((int) (alphaBytes * alpha)) << 24;
328e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return color;
329e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
330e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
331e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
332e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @Override
333e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
334e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            throws XmlPullParserException, IOException {
335e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final TypedArray a = obtainAttributes(res, theme,  attrs,R.styleable.VectorDrawable);
336e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        updateStateFromTypedArray(a);
337e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        a.recycle();
338e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
339e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final VectorDrawableState state = mVectorState;
340e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        state.mVPathRenderer = inflateInternal(res, parser, attrs, theme);
341e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
342e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
343e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        state.mVPathRenderer.setColorFilter(mTintFilter);
344e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
345e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
346e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private void updateStateFromTypedArray(TypedArray a) {
347e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final VectorDrawableState state = mVectorState;
348e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
349e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // Extract the theme attributes, if any.
350e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        state.mThemeAttrs = a.extractThemeAttrs();
351e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
352e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final int tintMode = a.getInt(R.styleable.VectorDrawable_tintMode, -1);
353e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (tintMode != -1) {
354e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            state.mTintMode = Drawable.parseTintMode(tintMode, Mode.SRC_IN);
355e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
356e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
357e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final ColorStateList tint = a.getColorStateList(R.styleable.VectorDrawable_tint);
358e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (tint != null) {
359e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            state.mTint = tint;
360e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
361e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
362e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
363e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private VPathRenderer inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
364e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            throws XmlPullParserException, IOException {
365e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final VPathRenderer pathRenderer = new VPathRenderer();
366e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
367e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        boolean noSizeTag = true;
368e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        boolean noViewportTag = true;
369e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        boolean noPathTag = true;
370e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
371e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // Use a stack to help to build the group tree.
372e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // The top of the stack is always the current group.
373e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final Stack<VGroup> groupStack = new Stack<VGroup>();
374e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        groupStack.push(pathRenderer.mRootGroup);
375e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
376e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int eventType = parser.getEventType();
377e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        while (eventType != XmlPullParser.END_DOCUMENT) {
378e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (eventType == XmlPullParser.START_TAG) {
379e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                final String tagName = parser.getName();
380e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                final VGroup currentGroup = groupStack.peek();
381e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
382e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (SHAPE_PATH.equals(tagName)) {
383e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    final VPath path = new VPath();
384e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    path.inflate(res, attrs, theme);
385e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    currentGroup.add(path);
386e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    if (path.getPathName() != null) {
387e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        mVGTargetsMap.put(path.getPathName(), path);
388e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
389e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    noPathTag = false;
390e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                } else if (SHAPE_SIZE.equals(tagName)) {
391e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    pathRenderer.parseSize(res, attrs);
392e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    noSizeTag = false;
393e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                } else if (SHAPE_VIEWPORT.equals(tagName)) {
394e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    pathRenderer.parseViewport(res, attrs);
395e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    noViewportTag = false;
396e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                } else if (SHAPE_GROUP.equals(tagName)) {
397e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    VGroup newChildGroup = new VGroup();
398e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    newChildGroup.inflate(res, attrs, theme);
399e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    currentGroup.mChildGroupList.add(newChildGroup);
400e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    groupStack.push(newChildGroup);
401e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    if (newChildGroup.getGroupName() != null) {
402e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        mVGTargetsMap.put(newChildGroup.getGroupName(), newChildGroup);
403e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
404e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
405e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            } else if (eventType == XmlPullParser.END_TAG) {
406e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                final String tagName = parser.getName();
407e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (SHAPE_GROUP.equals(tagName)) {
408e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    groupStack.pop();
409e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
410e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
411e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            eventType = parser.next();
412e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
413e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
414e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // Print the tree out for debug.
415e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (DBG_VECTOR_DRAWABLE) {
416e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            printGroupTree(pathRenderer.mRootGroup, 0);
417e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
418e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
419e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (noSizeTag || noViewportTag || noPathTag) {
420e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            final StringBuffer tag = new StringBuffer();
421e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
422e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (noSizeTag) {
423e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                tag.append(SHAPE_SIZE);
424e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
425e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
426e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (noViewportTag) {
427e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (tag.length() > 0) {
428e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    tag.append(" & ");
429e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
430e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                tag.append(SHAPE_SIZE);
431e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
432e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
433e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (noPathTag) {
434e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (tag.length() > 0) {
435e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    tag.append(" or ");
436e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
437e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                tag.append(SHAPE_PATH);
438e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
439e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
440e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            throw new XmlPullParserException("no " + tag + " defined");
441e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
442e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
443e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return pathRenderer;
444e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
445e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
446e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private void printGroupTree(VGroup currentGroup, int level) {
447e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        String indent = "";
448e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        for (int i = 0 ; i < level ; i++) {
449e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            indent += "    ";
450e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
451e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // Print the current node
452e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Log.v(LOGTAG, indent + "current group is :" +  currentGroup.getGroupName()
453e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                + " rotation is " + currentGroup.mRotate);
454e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Log.v(LOGTAG, indent + "matrix is :" +  currentGroup.getLocalMatrix().toString());
455e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // Then print all the children
456e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        for (int i = 0 ; i < currentGroup.mChildGroupList.size(); i++) {
457e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            printGroupTree(currentGroup.mChildGroupList.get(i), level + 1);
458e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
459e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
460e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
461e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static class VectorDrawableState extends ConstantState {
462e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int[] mThemeAttrs;
463e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int mChangingConfigurations;
464e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        VPathRenderer mVPathRenderer;
465e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Rect mPadding;
466e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        ColorStateList mTint;
467e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Mode mTintMode;
468e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
469e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public VectorDrawableState(VectorDrawableState copy) {
470e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (copy != null) {
471e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mThemeAttrs = copy.mThemeAttrs;
472e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mChangingConfigurations = copy.mChangingConfigurations;
473e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                // TODO: Make sure the constant state are handled correctly.
474e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mVPathRenderer = new VPathRenderer(copy.mVPathRenderer);
475e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mPadding = new Rect(copy.mPadding);
476e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mTint = copy.mTint;
477e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mTintMode = copy.mTintMode;
478e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
479e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
480e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
481e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        @Override
482e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public Drawable newDrawable() {
483e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return new VectorDrawable(this, null, null);
484e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
485e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
486e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        @Override
487e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public Drawable newDrawable(Resources res) {
488e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return new VectorDrawable(this, res, null);
489e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
490e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
491e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        @Override
492e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public Drawable newDrawable(Resources res, Theme theme) {
493e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return new VectorDrawable(this, res, theme);
494e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
495e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
496e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        @Override
497e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public int getChangingConfigurations() {
498e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return mChangingConfigurations;
499e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
500e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
501e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
502e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static class VPathRenderer {
503e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        /* Right now the internal data structure is organized as a tree.
504e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka         * Each node can be a group node, or a path.
505e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka         * A group node can have groups or paths as children, but a path node has
506e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka         * no children.
507e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka         * One example can be:
508e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka         *                 Root Group
509e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka         *                /    |     \
510e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka         *           Group    Path    Group
511e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka         *          /     \             |
512e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka         *         Path   Path         Path
513e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka         *
514e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka         */
515e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private final VGroup mRootGroup;
516e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
517e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private final Path mPath = new Path();
518e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private final Path mRenderPath = new Path();
519e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private static final Matrix IDENTITY_MATRIX = new Matrix();
520e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
521e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private Paint mStrokePaint;
522e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private Paint mFillPaint;
523e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private ColorFilter mColorFilter;
524e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private PathMeasure mPathMeasure;
525e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
526e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private float mBaseWidth = 0;
527e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private float mBaseHeight = 0;
528e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private float mViewportWidth = 0;
529e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private float mViewportHeight = 0;
530e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private int mRootAlpha = 0xFF;
531e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
532e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private final Matrix mFinalPathMatrix = new Matrix();
533e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
534e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public VPathRenderer() {
535e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mRootGroup = new VGroup();
536e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
537e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
538e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void setRootAlpha(int alpha) {
539e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mRootAlpha = alpha;
540e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
541e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
542e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public int getRootAlpha() {
543e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return mRootAlpha;
544e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
545e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
546e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public VPathRenderer(VPathRenderer copy) {
547e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mRootGroup = copy.mRootGroup;
548e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mBaseWidth = copy.mBaseWidth;
549e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mBaseHeight = copy.mBaseHeight;
550e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mViewportWidth = copy.mViewportHeight;
551e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mViewportHeight = copy.mViewportHeight;
552e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
553e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
554e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public boolean canApplyTheme() {
555e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            // If one of the paths can apply theme, then return true;
556e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return recursiveCanApplyTheme(mRootGroup);
557e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
558e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
559e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private boolean recursiveCanApplyTheme(VGroup currentGroup) {
560e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            // We can do a tree traverse here, if there is one path return true,
561e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            // then we return true for the whole tree.
562e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            final ArrayList<VPath> paths = currentGroup.mPathList;
563e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            for (int j = paths.size() - 1; j >= 0; j--) {
564e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                final VPath path = paths.get(j);
565e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (path.canApplyTheme()) {
566e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    return true;
567e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
568e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
569e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
570e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            final ArrayList<VGroup> childGroups = currentGroup.mChildGroupList;
571e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
572e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            for (int i = 0; i < childGroups.size(); i++) {
573e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                VGroup childGroup = childGroups.get(i);
574e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (childGroup.canApplyTheme()
575e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        || recursiveCanApplyTheme(childGroup)) {
576e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    return true;
577e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
578e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
579e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return false;
580e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
581e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
582e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void applyTheme(Theme t) {
583e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            // Apply theme to every path of the tree.
584e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            recursiveApplyTheme(mRootGroup, t);
585e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
586e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
587e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private void recursiveApplyTheme(VGroup currentGroup, Theme t) {
588e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            // We can do a tree traverse here, apply theme to all paths which
589e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            // can apply theme.
590e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            final ArrayList<VPath> paths = currentGroup.mPathList;
591e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            for (int j = paths.size() - 1; j >= 0; j--) {
592e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                final VPath path = paths.get(j);
593e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (path.canApplyTheme()) {
594e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    path.applyTheme(t);
595e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
596e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
597e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
598e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            final ArrayList<VGroup> childGroups = currentGroup.mChildGroupList;
599e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
600e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            for (int i = 0; i < childGroups.size(); i++) {
601e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                VGroup childGroup = childGroups.get(i);
602e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (childGroup.canApplyTheme()) {
603e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    childGroup.applyTheme(t);
604e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
605e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                recursiveApplyTheme(childGroup, t);
606e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
607e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
608e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
609e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
610e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void setColorFilter(ColorFilter colorFilter) {
611e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mColorFilter = colorFilter;
612e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
613e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (mFillPaint != null) {
614e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mFillPaint.setColorFilter(colorFilter);
615e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
616e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
617e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (mStrokePaint != null) {
618e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mStrokePaint.setColorFilter(colorFilter);
619e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
620e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
621e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
622e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
623e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private void drawGroupTree(VGroup currentGroup, Matrix currentMatrix,
624e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                float currentAlpha, Canvas canvas, int w, int h) {
625e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            // Calculate current group's matrix by preConcat the parent's and
626e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            // and the current one on the top of the stack.
627e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            // Basically the Mfinal = Mviewport * M0 * M1 * M2;
628e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            // Mi the local matrix at level i of the group tree.
629e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            currentGroup.mStackedMatrix.set(currentMatrix);
630e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
631e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            currentGroup.mStackedMatrix.preConcat(currentGroup.mLocalMatrix);
632e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
633e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            float stackedAlpha = currentAlpha * currentGroup.mGroupAlpha;
634e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            drawPath(currentGroup, stackedAlpha, canvas, w, h);
635e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            // Draw the group tree in post order.
636e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            for (int i = 0 ; i < currentGroup.mChildGroupList.size(); i++) {
637e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                drawGroupTree(currentGroup.mChildGroupList.get(i),
638e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        currentGroup.mStackedMatrix, stackedAlpha, canvas, w, h);
639e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
640e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
641e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
642e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void draw(Canvas canvas, int w, int h) {
643e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            // Travese the tree in pre-order to draw.
644e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            drawGroupTree(mRootGroup, IDENTITY_MATRIX, ((float) mRootAlpha) / 0xFF, canvas, w, h);
645e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
646e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
647e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private void drawPath(VGroup vGroup, float stackedAlpha, Canvas canvas, int w, int h) {
648e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            final float scale = Math.min(h / mViewportHeight, w / mViewportWidth);
649e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
650e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mFinalPathMatrix.set(vGroup.mStackedMatrix);
651e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mFinalPathMatrix.postScale(scale, scale, mViewportWidth / 2f, mViewportHeight / 2f);
652e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mFinalPathMatrix.postTranslate(w / 2f - mViewportWidth / 2f, h / 2f - mViewportHeight / 2f);
653e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
654e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            ArrayList<VPath> paths = vGroup.getPaths();
655e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            for (int i = 0; i < paths.size(); i++) {
656e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                VPath vPath = paths.get(i);
657e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                vPath.toPath(mPath);
658e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                final Path path = mPath;
659e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
660e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (vPath.mTrimPathStart != 0.0f || vPath.mTrimPathEnd != 1.0f) {
661e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    float start = (vPath.mTrimPathStart + vPath.mTrimPathOffset) % 1.0f;
662e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    float end = (vPath.mTrimPathEnd + vPath.mTrimPathOffset) % 1.0f;
663e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
664e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    if (mPathMeasure == null) {
665e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        mPathMeasure = new PathMeasure();
666e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
667e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    mPathMeasure.setPath(mPath, false);
668e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
669e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    float len = mPathMeasure.getLength();
670e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    start = start * len;
671e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    end = end * len;
672e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    path.reset();
673e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    if (start > end) {
674e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        mPathMeasure.getSegment(start, len, path, true);
675e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        mPathMeasure.getSegment(0f, end, path, true);
676e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    } else {
677e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        mPathMeasure.getSegment(start, end, path, true);
678e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
679e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    path.rLineTo(0, 0); // fix bug in measure
680e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
681e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
682e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mRenderPath.reset();
683e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
684e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mRenderPath.addPath(path, mFinalPathMatrix);
685e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
686e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (vPath.mClip) {
687e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    canvas.clipPath(mRenderPath, Region.Op.REPLACE);
688e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                } else {
689e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                   if (vPath.mFillColor != 0) {
690e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        if (mFillPaint == null) {
691e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                            mFillPaint = new Paint();
692e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                            mFillPaint.setColorFilter(mColorFilter);
693e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                            mFillPaint.setStyle(Paint.Style.FILL);
694e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                            mFillPaint.setAntiAlias(true);
695e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        }
696e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        mFillPaint.setColor(applyAlpha(vPath.mFillColor, stackedAlpha));
697e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        canvas.drawPath(mRenderPath, mFillPaint);
698e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
699e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
700e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    if (vPath.mStrokeColor != 0) {
701e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        if (mStrokePaint == null) {
702e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                            mStrokePaint = new Paint();
703e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                            mStrokePaint.setColorFilter(mColorFilter);
704e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                            mStrokePaint.setStyle(Paint.Style.STROKE);
705e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                            mStrokePaint.setAntiAlias(true);
706e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        }
707e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
708e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        final Paint strokePaint = mStrokePaint;
709e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        if (vPath.mStrokeLineJoin != null) {
710e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                            strokePaint.setStrokeJoin(vPath.mStrokeLineJoin);
711e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        }
712e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
713e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        if (vPath.mStrokeLineCap != null) {
714e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                            strokePaint.setStrokeCap(vPath.mStrokeLineCap);
715e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        }
716e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
717e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        strokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale);
718e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
719e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        strokePaint.setColor(applyAlpha(vPath.mStrokeColor, stackedAlpha));
720e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        strokePaint.setStrokeWidth(vPath.mStrokeWidth * scale);
721e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        canvas.drawPath(mRenderPath, strokePaint);
722e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
723e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
724e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
725e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
726e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
727e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private void parseViewport(Resources r, AttributeSet attrs)
728e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                throws XmlPullParserException {
729e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport);
730e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mViewportWidth = a.getFloat(R.styleable.VectorDrawableViewport_viewportWidth, mViewportWidth);
731e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mViewportHeight = a.getFloat(R.styleable.VectorDrawableViewport_viewportHeight, mViewportHeight);
732e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
733e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (mViewportWidth <= 0) {
734e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                throw new XmlPullParserException(a.getPositionDescription() +
735e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        "<viewport> tag requires viewportWidth > 0");
736e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            } else if (mViewportHeight <= 0) {
737e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                throw new XmlPullParserException(a.getPositionDescription() +
738e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        "<viewport> tag requires viewportHeight > 0");
739e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
740e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
741e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            a.recycle();
742e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
743e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
744e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private void parseSize(Resources r, AttributeSet attrs)
745e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                throws XmlPullParserException  {
746e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableSize);
747e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mBaseWidth = a.getDimension(R.styleable.VectorDrawableSize_width, mBaseWidth);
748e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mBaseHeight = a.getDimension(R.styleable.VectorDrawableSize_height, mBaseHeight);
749e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
750e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (mBaseWidth <= 0) {
751e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                throw new XmlPullParserException(a.getPositionDescription() +
752e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        "<size> tag requires width > 0");
753e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            } else if (mBaseHeight <= 0) {
754e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                throw new XmlPullParserException(a.getPositionDescription() +
755e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        "<size> tag requires height > 0");
756e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
757e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
758e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            a.recycle();
759e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
760e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
761e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
762e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
763e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    static class VGroup {
764e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private final ArrayList<VPath> mPathList = new ArrayList<VPath>();
765e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private final ArrayList<VGroup> mChildGroupList = new ArrayList<VGroup>();
766e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
767e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private float mRotate = 0;
768e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private float mPivotX = 0;
769e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private float mPivotY = 0;
770e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private float mScaleX = 1;
771e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private float mScaleY = 1;
772e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private float mTranslateX = 0;
773e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private float mTranslateY = 0;
774e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private float mGroupAlpha = 1;
775e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
776e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // mLocalMatrix is parsed from the XML.
777e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private final Matrix mLocalMatrix = new Matrix();
778e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // mStackedMatrix is only used when drawing, it combines all the
779e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // parents' local matrices with the current one.
780e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private final Matrix mStackedMatrix = new Matrix();
781e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
782e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private int[] mThemeAttrs;
783e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
784e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private String mGroupName = null;
785e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
786e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        /* Getter and Setter */
787e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public float getRotation() {
788e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return mRotate;
789e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
790e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
791e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void setRotation(float rotation) {
792e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (rotation != mRotate) {
793e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mRotate = rotation;
794e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                updateLocalMatrix();
795e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
796e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
797e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
798e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public float getPivotX() {
799e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return mPivotX;
800e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
801e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
802e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void setPivotX(float pivotX) {
803e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (pivotX != mPivotX) {
804e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mPivotX = pivotX;
805e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                updateLocalMatrix();
806e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
807e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
808e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
809e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public float getPivotY() {
810e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return mPivotY;
811e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
812e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
813e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void setPivotY(float pivotY) {
814e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (pivotY != mPivotY) {
815e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mPivotY = pivotY;
816e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                updateLocalMatrix();
817e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
818e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
819e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
820e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public float getScaleX() {
821e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return mScaleX;
822e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
823e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
824e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void setScaleX(float scaleX) {
825e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (scaleX != mScaleX) {
826e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mScaleX = scaleX;
827e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                updateLocalMatrix();
828e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
829e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
830e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
831e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public float getScaleY() {
832e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return mScaleY;
833e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
834e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
835e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void setScaleY(float scaleY) {
836e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (scaleY != mScaleY) {
837e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mScaleY = scaleY;
838e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                updateLocalMatrix();
839e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
840e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
841e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
842e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public float getTranslateX() {
843e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return mTranslateX;
844e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
845e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
846e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void setTranslateX(float translateX) {
847e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (translateX != mTranslateX) {
848e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mTranslateX = translateX;
849e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                updateLocalMatrix();
850e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
851e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
852e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
853e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public float getTranslateY() {
854e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return mTranslateY;
855e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
856e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
857e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void setTranslateY(float translateY) {
858e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (translateY != mTranslateY) {
859e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mTranslateY = translateY;
860e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                updateLocalMatrix();
861e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
862e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
863e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
864e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public float getAlpha() {
865e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return mGroupAlpha;
866e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
867e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
868e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void setAlpha(float groupAlpha) {
869e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (groupAlpha != mGroupAlpha) {
870e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mGroupAlpha = groupAlpha;
871e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
872e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
873e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
874e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public String getGroupName() {
875e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return mGroupName;
876e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
877e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
878e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public Matrix getLocalMatrix() {
879e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return mLocalMatrix;
880e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
881e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
882e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void add(VPath path) {
883e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mPathList.add(path);
884e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka         }
885e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
886e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public boolean canApplyTheme() {
887e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return mThemeAttrs != null;
888e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
889e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
890e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void applyTheme(Theme t) {
891e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (mThemeAttrs == null) {
892e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                return;
893e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
894e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
895e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            final TypedArray a = t.resolveAttributes(
896e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    mThemeAttrs, R.styleable.VectorDrawablePath);
897e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
898e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate);
899e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX);
900e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY);
901e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mScaleX = a.getFloat(R.styleable.VectorDrawableGroup_scaleX, mScaleX);
902e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mScaleY = a.getFloat(R.styleable.VectorDrawableGroup_scaleY, mScaleY);
903e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mTranslateX = a.getFloat(R.styleable.VectorDrawableGroup_translateX, mTranslateX);
904e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mTranslateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY, mTranslateY);
905e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mGroupAlpha = a.getFloat(R.styleable.VectorDrawableGroup_alpha, mGroupAlpha);
906e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            updateLocalMatrix();
907e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (a.hasValue(R.styleable.VectorDrawableGroup_name)) {
908e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mGroupName = a.getString(R.styleable.VectorDrawableGroup_name);
909e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
910e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            a.recycle();
911e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
912e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
913e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void inflate(Resources res, AttributeSet attrs, Theme theme) {
914e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            final TypedArray a = obtainAttributes(res, theme, attrs, R.styleable.VectorDrawableGroup);
915e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            final int[] themeAttrs = a.extractThemeAttrs();
916e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
917e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mThemeAttrs = themeAttrs;
918e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            // NOTE: The set of attributes loaded here MUST match the
919e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            // set of attributes loaded in applyTheme.
920e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
921e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_rotation] == 0) {
922e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate);
923e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
924e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
925e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_pivotX] == 0) {
926e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX);
927e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
928e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
929e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_pivotY] == 0) {
930e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY);
931e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
932e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
933e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_scaleX] == 0) {
934e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mScaleX = a.getFloat(R.styleable.VectorDrawableGroup_scaleX, mScaleX);
935e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
936e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
937e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_scaleY] == 0) {
938e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mScaleY = a.getFloat(R.styleable.VectorDrawableGroup_scaleY, mScaleY);
939e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
940e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
941e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_translateX] == 0) {
942e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mTranslateX = a.getFloat(R.styleable.VectorDrawableGroup_translateX, mTranslateX);
943e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
944e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
945e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_translateY] == 0) {
946e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mTranslateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY, mTranslateY);
947e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
948e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
949e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_name] == 0) {
950e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mGroupName = a.getString(R.styleable.VectorDrawableGroup_name);
951e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
952e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
953e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_alpha] == 0) {
954e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mGroupAlpha = a.getFloat(R.styleable.VectorDrawableGroup_alpha, mGroupAlpha);
955e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
956e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
957e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            updateLocalMatrix();
958e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            a.recycle();
959e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
960e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
961e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private void updateLocalMatrix() {
962e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            // The order we apply is the same as the
963e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            // RenderNode.cpp::applyViewPropertyTransforms().
964e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mLocalMatrix.reset();
965e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mLocalMatrix.postTranslate(-mPivotX, -mPivotY);
966e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mLocalMatrix.postScale(mScaleX, mScaleY);
967e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mLocalMatrix.postRotate(mRotate, 0, 0);
968e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mLocalMatrix.postTranslate(mTranslateX + mPivotX, mTranslateY + mPivotY);
969e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
970e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
971e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        /**
972e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka         * Must return in order of adding
973e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka         * @return ordered list of paths
974e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka         */
975e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public ArrayList<VPath> getPaths() {
976e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return mPathList;
977e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
978e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
979e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
980e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
981e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static class VPath {
982e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private int[] mThemeAttrs;
983e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
984e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int mStrokeColor = 0;
985e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        float mStrokeWidth = 0;
986e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        float mStrokeOpacity = Float.NaN;
987e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int mFillColor = Color.BLACK;
988e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int mFillRule;
989e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        float mFillOpacity = Float.NaN;
990e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        float mTrimPathStart = 0;
991e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        float mTrimPathEnd = 1;
992e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        float mTrimPathOffset = 0;
993e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
994e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        boolean mClip = false;
995e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Paint.Cap mStrokeLineCap = Paint.Cap.BUTT;
996e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Paint.Join mStrokeLineJoin = Paint.Join.MITER;
997e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        float mStrokeMiterlimit = 4;
998e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
999e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private PathParser.PathDataNode[] mNode = null;
1000e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private String mPathName;
1001e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
1002e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public VPath() {
1003e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            // Empty constructor.
1004e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
1005e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
1006e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void toPath(Path path) {
1007e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            path.reset();
1008e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (mNode != null) {
1009e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                PathParser.PathDataNode.nodesToPath(mNode, path);
1010            }
1011        }
1012
1013        public String getPathName() {
1014            return mPathName;
1015        }
1016
1017        private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) {
1018            switch (id) {
1019                case LINECAP_BUTT:
1020                    return Paint.Cap.BUTT;
1021                case LINECAP_ROUND:
1022                    return Paint.Cap.ROUND;
1023                case LINECAP_SQUARE:
1024                    return Paint.Cap.SQUARE;
1025                default:
1026                    return defValue;
1027            }
1028        }
1029
1030        private Paint.Join getStrokeLineJoin(int id, Paint.Join defValue) {
1031            switch (id) {
1032                case LINEJOIN_MITER:
1033                    return Paint.Join.MITER;
1034                case LINEJOIN_ROUND:
1035                    return Paint.Join.ROUND;
1036                case LINEJOIN_BEVEL:
1037                    return Paint.Join.BEVEL;
1038                default:
1039                    return defValue;
1040            }
1041        }
1042
1043        /* Setters and Getters */
1044        int getStroke() {
1045            return mStrokeColor;
1046        }
1047
1048        void setStroke(int strokeColor) {
1049            mStrokeColor = strokeColor;
1050        }
1051
1052        float getStrokeWidth() {
1053            return mStrokeWidth;
1054        }
1055
1056        void setStrokeWidth(float strokeWidth) {
1057            mStrokeWidth = strokeWidth;
1058        }
1059
1060        float getStrokeOpacity() {
1061            return mStrokeOpacity;
1062        }
1063
1064        void setStrokeOpacity(float strokeOpacity) {
1065            mStrokeOpacity = strokeOpacity;
1066        }
1067
1068        int getFill() {
1069            return mFillColor;
1070        }
1071
1072        void setFill(int fillColor) {
1073            mFillColor = fillColor;
1074        }
1075
1076        float getFillOpacity() {
1077            return mFillOpacity;
1078        }
1079
1080        void setFillOpacity(float fillOpacity) {
1081            mFillOpacity = fillOpacity;
1082        }
1083
1084        float getTrimPathStart() {
1085            return mTrimPathStart;
1086        }
1087
1088        void setTrimPathStart(float trimPathStart) {
1089            mTrimPathStart = trimPathStart;
1090        }
1091
1092        float getTrimPathEnd() {
1093            return mTrimPathEnd;
1094        }
1095
1096        void setTrimPathEnd(float trimPathEnd) {
1097            mTrimPathEnd = trimPathEnd;
1098        }
1099
1100        float getTrimPathOffset() {
1101            return mTrimPathOffset;
1102        }
1103
1104        void setTrimPathOffset(float trimPathOffset) {
1105            mTrimPathOffset = trimPathOffset;
1106        }
1107
1108        public void inflate(Resources r, AttributeSet attrs, Theme theme) {
1109            final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawablePath);
1110            final int[] themeAttrs = a.extractThemeAttrs();
1111            mThemeAttrs = themeAttrs;
1112
1113            // NOTE: The set of attributes loaded here MUST match the
1114            // set of attributes loaded in applyTheme.
1115            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_clipToPath] == 0) {
1116                mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
1117            }
1118
1119            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_name] == 0) {
1120                mPathName = a.getString(R.styleable.VectorDrawablePath_name);
1121            }
1122
1123            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pathData] == 0) {
1124                mNode = PathParser.createNodesFromPathData(a.getString(
1125                        R.styleable.VectorDrawablePath_pathData));
1126            }
1127
1128            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fill] == 0) {
1129                mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor);
1130            }
1131
1132            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fillOpacity] == 0) {
1133                mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity);
1134            }
1135
1136            if (themeAttrs == null
1137                    || themeAttrs[R.styleable.VectorDrawablePath_strokeLineCap] == 0) {
1138                mStrokeLineCap = getStrokeLineCap(
1139                        a.getInt(R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
1140            }
1141
1142            if (themeAttrs == null
1143                    || themeAttrs[R.styleable.VectorDrawablePath_strokeLineJoin] == 0) {
1144                mStrokeLineJoin = getStrokeLineJoin(
1145                        a.getInt(R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
1146            }
1147
1148            if (themeAttrs == null
1149                    || themeAttrs[R.styleable.VectorDrawablePath_strokeMiterLimit] == 0) {
1150                mStrokeMiterlimit = a.getFloat(
1151                        R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
1152            }
1153
1154            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_stroke] == 0) {
1155                mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor);
1156            }
1157
1158            if (themeAttrs == null
1159                    || themeAttrs[R.styleable.VectorDrawablePath_strokeOpacity] == 0) {
1160                mStrokeOpacity = a.getFloat(
1161                        R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity);
1162            }
1163
1164            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_strokeWidth] == 0) {
1165                mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth);
1166            }
1167
1168            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_trimPathEnd] == 0) {
1169                mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd);
1170            }
1171
1172            if (themeAttrs == null
1173                    || themeAttrs[R.styleable.VectorDrawablePath_trimPathOffset] == 0) {
1174                mTrimPathOffset = a.getFloat(
1175                        R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
1176            }
1177
1178            if (themeAttrs == null
1179                    || themeAttrs[R.styleable.VectorDrawablePath_trimPathStart] == 0) {
1180                mTrimPathStart = a.getFloat(
1181                        R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
1182            }
1183
1184            updateColorAlphas();
1185
1186            a.recycle();
1187        }
1188
1189        public boolean canApplyTheme() {
1190            return mThemeAttrs != null;
1191        }
1192
1193        public void applyTheme(Theme t) {
1194            if (mThemeAttrs == null) {
1195                return;
1196            }
1197
1198            final TypedArray a = t.resolveAttributes(
1199                    mThemeAttrs, R.styleable.VectorDrawablePath);
1200
1201            mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
1202
1203            if (a.hasValue(R.styleable.VectorDrawablePath_name)) {
1204                mPathName = a.getString(R.styleable.VectorDrawablePath_name);
1205            }
1206
1207            if (a.hasValue(R.styleable.VectorDrawablePath_pathData)) {
1208                mNode = PathParser.createNodesFromPathData(a.getString(
1209                        R.styleable.VectorDrawablePath_pathData));
1210            }
1211
1212            mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor);
1213            mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity);
1214
1215            mStrokeLineCap = getStrokeLineCap(a.getInt(
1216                    R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
1217            mStrokeLineJoin = getStrokeLineJoin(a.getInt(
1218                    R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
1219            mStrokeMiterlimit = a.getFloat(
1220                    R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
1221            mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor);
1222            mStrokeOpacity = a.getFloat(
1223                    R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity);
1224            mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth);
1225
1226            mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd);
1227            mTrimPathOffset = a.getFloat(
1228                    R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
1229            mTrimPathStart = a.getFloat(
1230                    R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
1231
1232            updateColorAlphas();
1233            a.recycle();
1234        }
1235
1236        private void updateColorAlphas() {
1237            if (!Float.isNaN(mFillOpacity)) {
1238                mFillColor = applyAlpha(mFillColor, mFillOpacity);
1239            }
1240
1241            if (!Float.isNaN(mStrokeOpacity)) {
1242                mStrokeColor = applyAlpha(mStrokeColor, mStrokeOpacity);
1243            }
1244        }
1245    }
1246}
1247