VectorDrawable.java revision 9453b7cfd4bbb35467bd7f947f850bd154982fce
1abb7d134c02ac60091108c491dafb00877093170John Hoford/*
2abb7d134c02ac60091108c491dafb00877093170John Hoford * Copyright (C) 2014 The Android Open Source Project
3abb7d134c02ac60091108c491dafb00877093170John Hoford *
4abb7d134c02ac60091108c491dafb00877093170John Hoford * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5abb7d134c02ac60091108c491dafb00877093170John Hoford * in compliance with the License. You may obtain a copy of the License at
6abb7d134c02ac60091108c491dafb00877093170John Hoford *
7abb7d134c02ac60091108c491dafb00877093170John Hoford * http://www.apache.org/licenses/LICENSE-2.0
8abb7d134c02ac60091108c491dafb00877093170John Hoford *
9abb7d134c02ac60091108c491dafb00877093170John Hoford * Unless required by applicable law or agreed to in writing, software distributed under the License
10abb7d134c02ac60091108c491dafb00877093170John Hoford * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11abb7d134c02ac60091108c491dafb00877093170John Hoford * or implied. See the License for the specific language governing permissions and limitations under
12abb7d134c02ac60091108c491dafb00877093170John Hoford * the License.
13abb7d134c02ac60091108c491dafb00877093170John Hoford */
14abb7d134c02ac60091108c491dafb00877093170John Hoford
15abb7d134c02ac60091108c491dafb00877093170John Hofordpackage android.graphics.drawable;
16abb7d134c02ac60091108c491dafb00877093170John Hoford
17abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.animation.ObjectAnimator;
18abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.animation.ValueAnimator;
19abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.content.res.Resources;
20abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.content.res.TypedArray;
21abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.content.res.Resources.Theme;
22abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Canvas;
23abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.ColorFilter;
24abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Matrix;
25abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Paint;
26abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Path;
27abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.PathMeasure;
28abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.PixelFormat;
29abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Rect;
30abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Region;
31abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.util.AttributeSet;
32abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.util.Log;
33abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.util.Xml;
34abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.view.animation.AccelerateDecelerateInterpolator;
35abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.view.animation.Interpolator;
36abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.view.animation.LinearInterpolator;
37abb7d134c02ac60091108c491dafb00877093170John Hoford
38abb7d134c02ac60091108c491dafb00877093170John Hofordimport com.android.internal.R;
39abb7d134c02ac60091108c491dafb00877093170John Hoford
40abb7d134c02ac60091108c491dafb00877093170John Hofordimport org.xmlpull.v1.XmlPullParser;
41abb7d134c02ac60091108c491dafb00877093170John Hofordimport org.xmlpull.v1.XmlPullParserException;
42abb7d134c02ac60091108c491dafb00877093170John Hofordimport org.xmlpull.v1.XmlPullParserFactory;
43abb7d134c02ac60091108c491dafb00877093170John Hoford
44abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.io.IOException;
45abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.ArrayList;
46abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.Arrays;
47abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.Collection;
48abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.HashMap;
49abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.HashSet;
50abb7d134c02ac60091108c491dafb00877093170John Hoford/**
51abb7d134c02ac60091108c491dafb00877093170John Hoford * This lets you create a drawable based on an XML vector graphic
52abb7d134c02ac60091108c491dafb00877093170John Hoford * It can be defined in an XML file with the <code>&lt;vector></code> element.
53abb7d134c02ac60091108c491dafb00877093170John Hoford * <p/>
54abb7d134c02ac60091108c491dafb00877093170John Hoford * The vector drawable has 6 elements:
55abb7d134c02ac60091108c491dafb00877093170John Hoford * <p/>
56abb7d134c02ac60091108c491dafb00877093170John Hoford * <dl>
57177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui * <dt><code>&lt;vector></code></dt>
58fba3bad3870d607ecaed4f147788885c841c2ab3ztenghui * <dd>The attribute <code>android:trigger</code> defines a state change that
59abb7d134c02ac60091108c491dafb00877093170John Hoford * will drive the animation </dd>
60fba3bad3870d607ecaed4f147788885c841c2ab3ztenghui * <dd>The attribute <code>android:versionCode</code> defines the version of
61177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui * VectorDrawable </dd>
62abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;size></code></dt>
63abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Used to defined the intrinsic Width Height size of the drawable using
64abb7d134c02ac60091108c491dafb00877093170John Hoford * <code>android:width</code> and <code>android:height</code> </dd>
65abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;viewport></code></dt>
66abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Used to defined the size of the virtual canvas the paths are drawn on.
67abb7d134c02ac60091108c491dafb00877093170John Hoford * The size is defined using the attributes <code>android:viewportHeight
68abb7d134c02ac60091108c491dafb00877093170John Hoford * </code> <code>android:viewportWidth</code></dd>
69abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;group></code></dt>
70abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines a "key frame" in the animation if there is only one group the
71abb7d134c02ac60091108c491dafb00877093170John Hoford * drawable is static 2D image that has no animation.</dd>
72abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;path></code></dt>
73abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines paths to be drawn. The path elements must be within a group
74abb7d134c02ac60091108c491dafb00877093170John Hoford * <dl>
75abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:name</code>
76abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines the name of the path.</dd></dt>
77abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pathData</code>
78abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines path string.</dd></dt>
79abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:fill</code>
80abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines the color to fill the path (none if not present).</dd></dt>
81abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:stroke</code>
82abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines the color to draw the path outline (none if not present).</dd></dt>
83abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeWidth</code>
84abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The width a path stroke</dd></dt>
85abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeOpacity</code>
86abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The opacity of a path stroke</dd></dt>
87abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:rotation</code>
88abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The amount to rotation the path stroke.</dd></dt>
89abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pivotX</code>
90abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The X coordinate of the center of rotation of a path</dd></dt>
91abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pivotY</code>
92abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The Y coordinate of the center of rotation of a path</dd></dt>
93abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:fillOpacity</code>
94abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The opacity to fill the path with</dd></dt>
95abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathStart</code>
96abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The fraction of the path to trim from the start from 0 to 1</dd></dt>
97abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathEnd</code>
98abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The fraction of the path to trim from the end from 0 to 1</dd></dt>
99abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathOffset</code>
100abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Shift trim region (allows showed region to include the start and end) from 0 to 1</dd></dt>
101abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:clipToPath</code>
102abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Path will set the clip path</dd></dt>
103abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeLineCap</code>
104abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the linecap for a stroked path: butt, round, square</dd></dt>
105abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeLineJoin</code>
106abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the lineJoin for a stroked path: miter,round,bevel</dd></dt>
107abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeMiterLimit</code>
108abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the Miter limit for a stroked path</dd></dt>
109abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_pressed</code>
110abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
111abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_focused</code>
112abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
113abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_selected</code>
114abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
115abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_window_focused</code>
116abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
117abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_enabled</code>
118abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
119abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_activated</code>
120abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
121abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_accelerated</code>
122abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
123abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_hovered</code>
124abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
125abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_checked</code>
126abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
127abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_checkable</code>
128abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
129abb7d134c02ac60091108c491dafb00877093170John Hoford * </dl>
130abb7d134c02ac60091108c491dafb00877093170John Hoford * </dd>
131abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;animation></code></dt>
132abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Used to customize the transition between two paths
133abb7d134c02ac60091108c491dafb00877093170John Hoford * <dl>
134abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:sequence</code>
135abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Configures this animation sequence between the named paths.</dd></dt>
136abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:limitTo</code>
137abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Limits an animation to only interpolate the selected variable
138abb7d134c02ac60091108c491dafb00877093170John Hoford * unlimited, path, rotation, trimPathStart, trimPathEnd, trimPathOffset</dd></dt>
139abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:repeatCount</code>
140abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Number of times to loop this aspect of the animation</dd></dt>
141abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:durations</code>
142abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The duration of each step in the animation in milliseconds
143abb7d134c02ac60091108c491dafb00877093170John Hoford * Must contain the number of named paths - 1</dd></dt>
144abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:startDelay</code>
145abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd></dd></dt>
146abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:repeatStyle</code>
147abb7d134c02ac60091108c491dafb00877093170John Hoford *  <dd>when repeating how does it repeat back and forth or a to b: forward, inAndOut</dd></dt>
148abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:animate</code>
149abb7d134c02ac60091108c491dafb00877093170John Hoford *  <dd>linear, accelerate, decelerate, easing</dd></dt>
150abb7d134c02ac60091108c491dafb00877093170John Hoford * </dl>
151abb7d134c02ac60091108c491dafb00877093170John Hoford * </dd>
152abb7d134c02ac60091108c491dafb00877093170John Hoford */
153abb7d134c02ac60091108c491dafb00877093170John Hofordpublic class VectorDrawable extends Drawable {
1549453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    private static final String LOGTAG = VectorDrawable.class.getSimpleName();
1559453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
156abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_SIZE = "size";
157abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_VIEWPORT = "viewport";
158abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_GROUP = "group";
159abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_PATH = "path";
160abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_TRANSITION = "transition";
161abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_ANIMATION = "animation";
162abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_VECTOR = "vector";
163abb7d134c02ac60091108c491dafb00877093170John Hoford
164abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINECAP_BUTT = 0;
165abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINECAP_ROUND = 1;
166abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINECAP_SQUARE = 2;
1679453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
168abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINEJOIN_MITER = 0;
169abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINEJOIN_ROUND = 1;
170abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINEJOIN_BEVEL = 2;
1719453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
172abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int DEFAULT_DURATION = 1000;
173abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final long DEFAULT_INFINITE_DURATION = 60 * 60 * 1000;
1749453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
175abb7d134c02ac60091108c491dafb00877093170John Hoford    private VectorDrawableState mVectorState;
176abb7d134c02ac60091108c491dafb00877093170John Hoford    private int mAlpha = 0xFF;
177abb7d134c02ac60091108c491dafb00877093170John Hoford
178abb7d134c02ac60091108c491dafb00877093170John Hoford    public VectorDrawable() {
1799453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        mVectorState = new VectorDrawableState(null);
180abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mBasicAnimator = ObjectAnimator.ofFloat(this, "AnimationFraction", 0, 1);
1819453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
182abb7d134c02ac60091108c491dafb00877093170John Hoford        setDuration(DEFAULT_DURATION);
183abb7d134c02ac60091108c491dafb00877093170John Hoford    }
184abb7d134c02ac60091108c491dafb00877093170John Hoford
1859453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    private VectorDrawable(VectorDrawableState state, Resources res, Theme theme) {
186abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState = new VectorDrawableState(state);
187abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mBasicAnimator = ObjectAnimator.ofFloat(this, "AnimationFraction", 0, 1);
1889453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1899453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        if (theme != null && canApplyTheme()) {
1909453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            applyTheme(theme);
1919453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
1929453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
193abb7d134c02ac60091108c491dafb00877093170John Hoford        long duration = mVectorState.mVAnimatedPath.getTotalAnimationDuration();
194abb7d134c02ac60091108c491dafb00877093170John Hoford        if (duration == -1) { // if it set to infinite set to 1 hour
195abb7d134c02ac60091108c491dafb00877093170John Hoford            duration = DEFAULT_INFINITE_DURATION; // TODO define correct approach for infinite
196abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mBasicAnimator.setFloatValues(0, duration / 1000);
197abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mBasicAnimator.setInterpolator(new LinearInterpolator());
198abb7d134c02ac60091108c491dafb00877093170John Hoford        }
199abb7d134c02ac60091108c491dafb00877093170John Hoford        setDuration(duration);
200abb7d134c02ac60091108c491dafb00877093170John Hoford    }
201abb7d134c02ac60091108c491dafb00877093170John Hoford
202abb7d134c02ac60091108c491dafb00877093170John Hoford    final static class VectorDrawableState extends ConstantState {
2039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        int[] mThemeAttrs;
204abb7d134c02ac60091108c491dafb00877093170John Hoford        int mChangingConfigurations;
205abb7d134c02ac60091108c491dafb00877093170John Hoford        ValueAnimator mBasicAnimator;
206abb7d134c02ac60091108c491dafb00877093170John Hoford        VAnimatedPath mVAnimatedPath = new VAnimatedPath();
207abb7d134c02ac60091108c491dafb00877093170John Hoford        Rect mPadding;
208abb7d134c02ac60091108c491dafb00877093170John Hoford        int mIntrinsicHeight;
209abb7d134c02ac60091108c491dafb00877093170John Hoford        int mIntrinsicWidth;
210abb7d134c02ac60091108c491dafb00877093170John Hoford
2119453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public VectorDrawableState(VectorDrawableState copy) {
2129453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (copy != null) {
2139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mChangingConfigurations = copy.mChangingConfigurations;
2149453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mVAnimatedPath = new VAnimatedPath(copy.mVAnimatedPath);
2159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mPadding = new Rect(copy.mPadding);
2169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mIntrinsicHeight = copy.mIntrinsicHeight;
2179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mIntrinsicWidth = copy.mIntrinsicWidth;
2189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
219abb7d134c02ac60091108c491dafb00877093170John Hoford        }
220abb7d134c02ac60091108c491dafb00877093170John Hoford
2219453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        @Override
2229453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public Drawable newDrawable() {
2239453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return new VectorDrawable(this, null, null);
224abb7d134c02ac60091108c491dafb00877093170John Hoford        }
225abb7d134c02ac60091108c491dafb00877093170John Hoford
226abb7d134c02ac60091108c491dafb00877093170John Hoford        @Override
2279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public Drawable newDrawable(Resources res) {
2289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return new VectorDrawable(this, res, null);
2299453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
2309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
2319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        @Override
2329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public Drawable newDrawable(Resources res, Theme theme) {
2339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return new VectorDrawable(this, res, theme);
234abb7d134c02ac60091108c491dafb00877093170John Hoford        }
235abb7d134c02ac60091108c491dafb00877093170John Hoford
236abb7d134c02ac60091108c491dafb00877093170John Hoford        @Override
237abb7d134c02ac60091108c491dafb00877093170John Hoford        public int getChangingConfigurations() {
238abb7d134c02ac60091108c491dafb00877093170John Hoford            return mChangingConfigurations;
239abb7d134c02ac60091108c491dafb00877093170John Hoford        }
240abb7d134c02ac60091108c491dafb00877093170John Hoford    }
241abb7d134c02ac60091108c491dafb00877093170John Hoford
242abb7d134c02ac60091108c491dafb00877093170John Hoford    /* (non-Javadoc)
243abb7d134c02ac60091108c491dafb00877093170John Hoford     * @see android.graphics.drawable.Drawable#getConstantState()
244abb7d134c02ac60091108c491dafb00877093170John Hoford     */
245abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
246abb7d134c02ac60091108c491dafb00877093170John Hoford    public ConstantState getConstantState() {
247abb7d134c02ac60091108c491dafb00877093170John Hoford        return mVectorState;
248abb7d134c02ac60091108c491dafb00877093170John Hoford    }
249abb7d134c02ac60091108c491dafb00877093170John Hoford
250abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
251abb7d134c02ac60091108c491dafb00877093170John Hoford     * start the animation
252abb7d134c02ac60091108c491dafb00877093170John Hoford     */
253abb7d134c02ac60091108c491dafb00877093170John Hoford    public void start() {
254abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mBasicAnimator.start();
255abb7d134c02ac60091108c491dafb00877093170John Hoford    }
256abb7d134c02ac60091108c491dafb00877093170John Hoford
257abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
258abb7d134c02ac60091108c491dafb00877093170John Hoford     * Stop the animation.
259abb7d134c02ac60091108c491dafb00877093170John Hoford     */
260abb7d134c02ac60091108c491dafb00877093170John Hoford    public void stop() {
261abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mBasicAnimator.end();
262abb7d134c02ac60091108c491dafb00877093170John Hoford    }
263abb7d134c02ac60091108c491dafb00877093170John Hoford
264abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
265abb7d134c02ac60091108c491dafb00877093170John Hoford     * Get the current time point in the animation
266abb7d134c02ac60091108c491dafb00877093170John Hoford     *
267abb7d134c02ac60091108c491dafb00877093170John Hoford     * @return the current point on the animation
268abb7d134c02ac60091108c491dafb00877093170John Hoford     */
269abb7d134c02ac60091108c491dafb00877093170John Hoford    public float geAnimationFraction() {
270abb7d134c02ac60091108c491dafb00877093170John Hoford        return mVectorState.mVAnimatedPath.getValue();
271abb7d134c02ac60091108c491dafb00877093170John Hoford    }
272abb7d134c02ac60091108c491dafb00877093170John Hoford
273abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
274abb7d134c02ac60091108c491dafb00877093170John Hoford     * set the time point in the animation
275abb7d134c02ac60091108c491dafb00877093170John Hoford     *
276abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param value the point along the animation typically between 0 and 1
277abb7d134c02ac60091108c491dafb00877093170John Hoford     */
278abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setAnimationFraction(float value) {
279abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mVAnimatedPath.setAnimationFraction(value);
280abb7d134c02ac60091108c491dafb00877093170John Hoford        invalidateSelf();
281abb7d134c02ac60091108c491dafb00877093170John Hoford    }
282abb7d134c02ac60091108c491dafb00877093170John Hoford
283abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
284abb7d134c02ac60091108c491dafb00877093170John Hoford     * set the amount of time the animation will take
285abb7d134c02ac60091108c491dafb00877093170John Hoford     *
286abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param duration amount of time in milliseconds
287abb7d134c02ac60091108c491dafb00877093170John Hoford     */
288abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setDuration(long duration) {
289abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mBasicAnimator.setDuration(duration);
290abb7d134c02ac60091108c491dafb00877093170John Hoford    }
291abb7d134c02ac60091108c491dafb00877093170John Hoford
292abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
293abb7d134c02ac60091108c491dafb00877093170John Hoford     * Defines what this animation should do when it reaches the end. This setting is applied only
294abb7d134c02ac60091108c491dafb00877093170John Hoford     * when the repeat count is either greater than 0 or {@link #INFINITE}.
295abb7d134c02ac60091108c491dafb00877093170John Hoford     */
296abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setRepeatMode(int mode) {
297abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mBasicAnimator.setRepeatMode(mode);
298abb7d134c02ac60091108c491dafb00877093170John Hoford    }
299abb7d134c02ac60091108c491dafb00877093170John Hoford
300abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
301abb7d134c02ac60091108c491dafb00877093170John Hoford     * Sets animation to repeat
302abb7d134c02ac60091108c491dafb00877093170John Hoford     *
303abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param repeat True if this drawable repeats its animation
304abb7d134c02ac60091108c491dafb00877093170John Hoford     */
305abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setRepeatCount(int repeat) {
306abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mBasicAnimator.setRepeatCount(repeat);
307abb7d134c02ac60091108c491dafb00877093170John Hoford    }
308abb7d134c02ac60091108c491dafb00877093170John Hoford
309abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
310abb7d134c02ac60091108c491dafb00877093170John Hoford     * @return True if this drawable repeats its animation
311abb7d134c02ac60091108c491dafb00877093170John Hoford     */
312abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getRepeatCount() {
313abb7d134c02ac60091108c491dafb00877093170John Hoford        return mVectorState.mBasicAnimator.getRepeatCount();
314abb7d134c02ac60091108c491dafb00877093170John Hoford    }
315abb7d134c02ac60091108c491dafb00877093170John Hoford
316abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
317abb7d134c02ac60091108c491dafb00877093170John Hoford    public boolean isStateful() {
318abb7d134c02ac60091108c491dafb00877093170John Hoford        return true;
319abb7d134c02ac60091108c491dafb00877093170John Hoford    }
320abb7d134c02ac60091108c491dafb00877093170John Hoford
321abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
322abb7d134c02ac60091108c491dafb00877093170John Hoford    protected boolean onStateChange(int[] state) {
323abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mVAnimatedPath.setState(state);
324abb7d134c02ac60091108c491dafb00877093170John Hoford        int direction = mVectorState.mVAnimatedPath.getTrigger(state);
325abb7d134c02ac60091108c491dafb00877093170John Hoford        if (direction>0) {
326abb7d134c02ac60091108c491dafb00877093170John Hoford            animateForward();
327abb7d134c02ac60091108c491dafb00877093170John Hoford        } else if (direction<0) {
328abb7d134c02ac60091108c491dafb00877093170John Hoford            animateBackward();
329abb7d134c02ac60091108c491dafb00877093170John Hoford        }
330abb7d134c02ac60091108c491dafb00877093170John Hoford        super.onStateChange(state);
331abb7d134c02ac60091108c491dafb00877093170John Hoford        invalidateSelf();
332abb7d134c02ac60091108c491dafb00877093170John Hoford        return true;
333abb7d134c02ac60091108c491dafb00877093170John Hoford    }
334abb7d134c02ac60091108c491dafb00877093170John Hoford
335abb7d134c02ac60091108c491dafb00877093170John Hoford    private void animateForward(){
336abb7d134c02ac60091108c491dafb00877093170John Hoford        if (!mVectorState.mBasicAnimator.isStarted()) {
337abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mBasicAnimator.setFloatValues(0,1);
338abb7d134c02ac60091108c491dafb00877093170John Hoford            start();
339abb7d134c02ac60091108c491dafb00877093170John Hoford        }
340abb7d134c02ac60091108c491dafb00877093170John Hoford    }
341abb7d134c02ac60091108c491dafb00877093170John Hoford
342abb7d134c02ac60091108c491dafb00877093170John Hoford    private void animateBackward(){
343abb7d134c02ac60091108c491dafb00877093170John Hoford        if (!mVectorState.mBasicAnimator.isStarted()) {
344abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mBasicAnimator.setFloatValues(.99f,0);
345abb7d134c02ac60091108c491dafb00877093170John Hoford            start();
346abb7d134c02ac60091108c491dafb00877093170John Hoford        }
347abb7d134c02ac60091108c491dafb00877093170John Hoford    }
348abb7d134c02ac60091108c491dafb00877093170John Hoford
349abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
350abb7d134c02ac60091108c491dafb00877093170John Hoford    public void draw(Canvas canvas) {
351abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mVAnimatedPath.draw(canvas);
352abb7d134c02ac60091108c491dafb00877093170John Hoford    }
353abb7d134c02ac60091108c491dafb00877093170John Hoford
354abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
355abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setAlpha(int alpha) {
356abb7d134c02ac60091108c491dafb00877093170John Hoford        // TODO correct handling of transparent
357abb7d134c02ac60091108c491dafb00877093170John Hoford        if (mAlpha != alpha) {
358abb7d134c02ac60091108c491dafb00877093170John Hoford            mAlpha = alpha;
359abb7d134c02ac60091108c491dafb00877093170John Hoford            invalidateSelf();
360abb7d134c02ac60091108c491dafb00877093170John Hoford        }
361abb7d134c02ac60091108c491dafb00877093170John Hoford    }
362abb7d134c02ac60091108c491dafb00877093170John Hoford
363abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
364abb7d134c02ac60091108c491dafb00877093170John Hoford     * Not implemented yet
365abb7d134c02ac60091108c491dafb00877093170John Hoford     * @hide
366abb7d134c02ac60091108c491dafb00877093170John Hoford     */
367abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
368abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setColorFilter(ColorFilter colorFilter) {
369abb7d134c02ac60091108c491dafb00877093170John Hoford        // TODO: support color filter
370abb7d134c02ac60091108c491dafb00877093170John Hoford    }
371abb7d134c02ac60091108c491dafb00877093170John Hoford
372abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
373abb7d134c02ac60091108c491dafb00877093170John Hoford     * Returns a {@link android.graphics.PixelFormat graphics.PixelFormat}
374abb7d134c02ac60091108c491dafb00877093170John Hoford     * value of TRANSLUCENT.
375abb7d134c02ac60091108c491dafb00877093170John Hoford     */
376abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
377abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getOpacity() {
378abb7d134c02ac60091108c491dafb00877093170John Hoford        return PixelFormat.TRANSLUCENT;
379abb7d134c02ac60091108c491dafb00877093170John Hoford    }
380abb7d134c02ac60091108c491dafb00877093170John Hoford
381abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
382abb7d134c02ac60091108c491dafb00877093170John Hoford     * Sets padding for this shape, defined by a Rect object. Define the padding in the Rect object
383abb7d134c02ac60091108c491dafb00877093170John Hoford     * as: left, top, right, bottom.
384abb7d134c02ac60091108c491dafb00877093170John Hoford     */
385abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setPadding(Rect padding) {
386abb7d134c02ac60091108c491dafb00877093170John Hoford        setPadding(padding.left, padding.top, padding.right, padding.bottom);
387abb7d134c02ac60091108c491dafb00877093170John Hoford    }
388abb7d134c02ac60091108c491dafb00877093170John Hoford
389abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
390abb7d134c02ac60091108c491dafb00877093170John Hoford     * Sets padding for the shape.
391abb7d134c02ac60091108c491dafb00877093170John Hoford     *
392abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param left padding for the left side (in pixels)
393abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param top padding for the top (in pixels)
394abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param right padding for the right side (in pixels)
395abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param bottom padding for the bottom (in pixels)
396abb7d134c02ac60091108c491dafb00877093170John Hoford     */
397abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setPadding(int left, int top, int right, int bottom) {
398abb7d134c02ac60091108c491dafb00877093170John Hoford        if ((left | top | right | bottom) == 0) {
399abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mPadding = null;
400abb7d134c02ac60091108c491dafb00877093170John Hoford        } else {
401abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mVectorState.mPadding == null) {
402abb7d134c02ac60091108c491dafb00877093170John Hoford                mVectorState.mPadding = new Rect();
403abb7d134c02ac60091108c491dafb00877093170John Hoford            }
404abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mPadding.set(left, top, right, bottom);
405abb7d134c02ac60091108c491dafb00877093170John Hoford        }
406abb7d134c02ac60091108c491dafb00877093170John Hoford        invalidateSelf();
407abb7d134c02ac60091108c491dafb00877093170John Hoford    }
408abb7d134c02ac60091108c491dafb00877093170John Hoford
409abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
410abb7d134c02ac60091108c491dafb00877093170John Hoford     * Sets the intrinsic (default) width for this shape.
411abb7d134c02ac60091108c491dafb00877093170John Hoford     *
412abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param width the intrinsic width (in pixels)
413abb7d134c02ac60091108c491dafb00877093170John Hoford     */
414abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setIntrinsicWidth(int width) {
415abb7d134c02ac60091108c491dafb00877093170John Hoford        if (mVectorState.mIntrinsicWidth != width) {
416abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mIntrinsicWidth = width;
417abb7d134c02ac60091108c491dafb00877093170John Hoford            invalidateSelf();
418abb7d134c02ac60091108c491dafb00877093170John Hoford        }
419abb7d134c02ac60091108c491dafb00877093170John Hoford    }
420abb7d134c02ac60091108c491dafb00877093170John Hoford
421abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
422abb7d134c02ac60091108c491dafb00877093170John Hoford     * Sets the intrinsic (default) height for this shape.
423abb7d134c02ac60091108c491dafb00877093170John Hoford     *
424abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param height the intrinsic height (in pixels)
425abb7d134c02ac60091108c491dafb00877093170John Hoford     */
426abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setIntrinsicHeight(int height) {
427abb7d134c02ac60091108c491dafb00877093170John Hoford        if (mVectorState.mIntrinsicHeight != height) {
428abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mIntrinsicHeight = height;
429abb7d134c02ac60091108c491dafb00877093170John Hoford            invalidateSelf();
430abb7d134c02ac60091108c491dafb00877093170John Hoford        }
431abb7d134c02ac60091108c491dafb00877093170John Hoford    }
432abb7d134c02ac60091108c491dafb00877093170John Hoford
433abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
434abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getIntrinsicWidth() {
435abb7d134c02ac60091108c491dafb00877093170John Hoford        return mVectorState.mIntrinsicWidth;
436abb7d134c02ac60091108c491dafb00877093170John Hoford    }
437abb7d134c02ac60091108c491dafb00877093170John Hoford
438abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
439abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getIntrinsicHeight() {
440abb7d134c02ac60091108c491dafb00877093170John Hoford        return mVectorState.mIntrinsicHeight;
441abb7d134c02ac60091108c491dafb00877093170John Hoford    }
442abb7d134c02ac60091108c491dafb00877093170John Hoford
443abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
444abb7d134c02ac60091108c491dafb00877093170John Hoford    public boolean getPadding(Rect padding) {
445abb7d134c02ac60091108c491dafb00877093170John Hoford        if (mVectorState.mPadding != null) {
446abb7d134c02ac60091108c491dafb00877093170John Hoford            padding.set(mVectorState.mPadding);
447abb7d134c02ac60091108c491dafb00877093170John Hoford            return true;
448abb7d134c02ac60091108c491dafb00877093170John Hoford        } else {
449abb7d134c02ac60091108c491dafb00877093170John Hoford            return super.getPadding(padding);
450abb7d134c02ac60091108c491dafb00877093170John Hoford        }
451abb7d134c02ac60091108c491dafb00877093170John Hoford    }
452abb7d134c02ac60091108c491dafb00877093170John Hoford
453abb7d134c02ac60091108c491dafb00877093170John Hoford    /** @hide */
454abb7d134c02ac60091108c491dafb00877093170John Hoford    public static VectorDrawable create(Resources resources, int rid) {
455abb7d134c02ac60091108c491dafb00877093170John Hoford        try {
456abb7d134c02ac60091108c491dafb00877093170John Hoford            VectorDrawable drawable = new VectorDrawable();
457abb7d134c02ac60091108c491dafb00877093170John Hoford            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
458abb7d134c02ac60091108c491dafb00877093170John Hoford            factory.setNamespaceAware(true);
459abb7d134c02ac60091108c491dafb00877093170John Hoford            XmlPullParser xpp = resources.getXml(rid);
460abb7d134c02ac60091108c491dafb00877093170John Hoford            AttributeSet attrs = Xml.asAttributeSet(xpp);
461abb7d134c02ac60091108c491dafb00877093170John Hoford            drawable.inflate(resources, xpp, attrs);
462abb7d134c02ac60091108c491dafb00877093170John Hoford            drawable.setAnimationFraction(0);
463abb7d134c02ac60091108c491dafb00877093170John Hoford            return drawable;
464abb7d134c02ac60091108c491dafb00877093170John Hoford        } catch (XmlPullParserException e) {
465abb7d134c02ac60091108c491dafb00877093170John Hoford            Log.e(LOGTAG, "parser error", e);
466abb7d134c02ac60091108c491dafb00877093170John Hoford        } catch (IOException e) {
467abb7d134c02ac60091108c491dafb00877093170John Hoford            Log.e(LOGTAG, "parser error", e);
468abb7d134c02ac60091108c491dafb00877093170John Hoford        }
469abb7d134c02ac60091108c491dafb00877093170John Hoford        return null;
470abb7d134c02ac60091108c491dafb00877093170John Hoford    }
471abb7d134c02ac60091108c491dafb00877093170John Hoford
472abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
473abb7d134c02ac60091108c491dafb00877093170John Hoford    public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
474abb7d134c02ac60091108c491dafb00877093170John Hoford            throws XmlPullParserException, IOException {
4759453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        final VAnimatedPath p = inflateInternal(res, parser, attrs, theme);
4769453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        setAnimatedPath(p);
477abb7d134c02ac60091108c491dafb00877093170John Hoford    }
478abb7d134c02ac60091108c491dafb00877093170John Hoford
4799453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    @Override
4809453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    public boolean canApplyTheme() {
4819453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        return super.canApplyTheme() || mVectorState != null && mVectorState.canApplyTheme();
4829453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    }
4839453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
4849453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    @Override
4859453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    public void applyTheme(Theme t) {
4869453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        super.applyTheme(t);
4879453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
4889453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        final VectorDrawableState state = mVectorState;
4899453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        final VAnimatedPath path = state.mVAnimatedPath;
4909453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        if (path != null && path.canApplyTheme()) {
4919453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            path.applyTheme(t);
4929453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
4939453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    }
4949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
4959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    private VAnimatedPath inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
4969453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            Theme theme) throws XmlPullParserException, IOException {
4979453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        final VAnimatedPath animatedPath = new VAnimatedPath();
4989453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
499abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noSizeTag = true;
500abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noViewportTag = true;
501abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noGroupTag = true;
502abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noPathTag = true;
5039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
5049453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        VGroup currentGroup = null;
505abb7d134c02ac60091108c491dafb00877093170John Hoford
506abb7d134c02ac60091108c491dafb00877093170John Hoford        int eventType = parser.getEventType();
507abb7d134c02ac60091108c491dafb00877093170John Hoford        while (eventType != XmlPullParser.END_DOCUMENT) {
508abb7d134c02ac60091108c491dafb00877093170John Hoford            if (eventType == XmlPullParser.START_TAG) {
5099453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final String tagName = parser.getName();
510abb7d134c02ac60091108c491dafb00877093170John Hoford                if (SHAPE_PATH.equals(tagName)) {
5119453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final VPath path = new VPath();
5129453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    path.inflate(res, attrs, theme);
5139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    currentGroup.add(path);
514abb7d134c02ac60091108c491dafb00877093170John Hoford                    noPathTag = false;
515abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_ANIMATION.equals(tagName)) {
5169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final VAnimation anim = new VAnimation();
5179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    anim.inflate(animatedPath.mGroupList, res, attrs, theme);
518abb7d134c02ac60091108c491dafb00877093170John Hoford                    animatedPath.addAnimation(anim);
519abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_SIZE.equals(tagName)) {
520abb7d134c02ac60091108c491dafb00877093170John Hoford                    animatedPath.parseSize(res, attrs);
521abb7d134c02ac60091108c491dafb00877093170John Hoford                    noSizeTag = false;
522abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_VIEWPORT.equals(tagName)) {
523abb7d134c02ac60091108c491dafb00877093170John Hoford                    animatedPath.parseViewport(res, attrs);
524abb7d134c02ac60091108c491dafb00877093170John Hoford                    noViewportTag = false;
525abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_GROUP.equals(tagName)) {
5269453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    currentGroup = new VGroup();
527abb7d134c02ac60091108c491dafb00877093170John Hoford                    animatedPath.mGroupList.add(currentGroup);
528abb7d134c02ac60091108c491dafb00877093170John Hoford                    noGroupTag = false;
529abb7d134c02ac60091108c491dafb00877093170John Hoford                }  else if (SHAPE_VECTOR.equals(tagName)) {
5309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final TypedArray a = res.obtainAttributes(attrs, R.styleable.VectorDrawable);
531abb7d134c02ac60091108c491dafb00877093170John Hoford                    animatedPath.setTrigger(a.getInteger(R.styleable.VectorDrawable_trigger, 0));
532177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui
533177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    // Parsing the version information.
534177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    // Right now, we only support version "1".
535177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    // If the xml didn't specify the version number, the default version is "1".
5369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final int versionCode = a.getInt(R.styleable.VectorDrawable_versionCode, 1);
537177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    if (versionCode != 1) {
538177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                        throw new IllegalArgumentException(
539177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                                "So far, VectorDrawable only support version 1");
540177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    }
541177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui
542abb7d134c02ac60091108c491dafb00877093170John Hoford                    a.recycle();
543abb7d134c02ac60091108c491dafb00877093170John Hoford                }
544abb7d134c02ac60091108c491dafb00877093170John Hoford            }
5459453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
546abb7d134c02ac60091108c491dafb00877093170John Hoford            eventType = parser.next();
547abb7d134c02ac60091108c491dafb00877093170John Hoford        }
5489453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
549abb7d134c02ac60091108c491dafb00877093170John Hoford        if (noSizeTag || noViewportTag || noGroupTag || noPathTag) {
5509453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final StringBuffer tag = new StringBuffer();
5519453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
552abb7d134c02ac60091108c491dafb00877093170John Hoford            if (noSizeTag) {
5539453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_SIZE);
554abb7d134c02ac60091108c491dafb00877093170John Hoford            }
5559453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
556abb7d134c02ac60091108c491dafb00877093170John Hoford            if  (noViewportTag){
557abb7d134c02ac60091108c491dafb00877093170John Hoford                if (tag.length()>0) {
558abb7d134c02ac60091108c491dafb00877093170John Hoford                    tag.append(" & ");
559abb7d134c02ac60091108c491dafb00877093170John Hoford                }
5609453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_SIZE);
561abb7d134c02ac60091108c491dafb00877093170John Hoford            }
5629453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
563abb7d134c02ac60091108c491dafb00877093170John Hoford            if  (noGroupTag){
564abb7d134c02ac60091108c491dafb00877093170John Hoford                if (tag.length()>0) {
565abb7d134c02ac60091108c491dafb00877093170John Hoford                    tag.append(" & ");
566abb7d134c02ac60091108c491dafb00877093170John Hoford                }
5679453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_GROUP);
568abb7d134c02ac60091108c491dafb00877093170John Hoford            }
5699453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
570abb7d134c02ac60091108c491dafb00877093170John Hoford            if  (noPathTag){
571abb7d134c02ac60091108c491dafb00877093170John Hoford                if (tag.length()>0) {
572abb7d134c02ac60091108c491dafb00877093170John Hoford                    tag.append(" or ");
573abb7d134c02ac60091108c491dafb00877093170John Hoford                }
5749453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_PATH);
575abb7d134c02ac60091108c491dafb00877093170John Hoford            }
5769453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
5779453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            throw new XmlPullParserException("no " + tag + " defined");
578abb7d134c02ac60091108c491dafb00877093170John Hoford        }
5799453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
580abb7d134c02ac60091108c491dafb00877093170John Hoford        // post parse cleanup
581abb7d134c02ac60091108c491dafb00877093170John Hoford        animatedPath.parseFinish();
582abb7d134c02ac60091108c491dafb00877093170John Hoford        return animatedPath;
583abb7d134c02ac60091108c491dafb00877093170John Hoford    }
584abb7d134c02ac60091108c491dafb00877093170John Hoford
585abb7d134c02ac60091108c491dafb00877093170John Hoford    private void setAnimatedPath(VAnimatedPath animatedPath) {
586abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mVAnimatedPath = animatedPath;
5879453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
588abb7d134c02ac60091108c491dafb00877093170John Hoford        setIntrinsicWidth((int) mVectorState.mVAnimatedPath.mBaseWidth);
589abb7d134c02ac60091108c491dafb00877093170John Hoford        setIntrinsicHeight((int) mVectorState.mVAnimatedPath.mBaseHeight);
5909453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
591abb7d134c02ac60091108c491dafb00877093170John Hoford        long duration = mVectorState.mVAnimatedPath.getTotalAnimationDuration();
592abb7d134c02ac60091108c491dafb00877093170John Hoford        if (duration == -1) { // if it set to infinite set to 1 hour
593abb7d134c02ac60091108c491dafb00877093170John Hoford            duration = DEFAULT_INFINITE_DURATION; // TODO define correct approach for infinite
594abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mBasicAnimator.setFloatValues(0, duration / 1000);
595abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mBasicAnimator.setInterpolator(new LinearInterpolator());
596abb7d134c02ac60091108c491dafb00877093170John Hoford        }
597abb7d134c02ac60091108c491dafb00877093170John Hoford
5989453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        setDuration(duration);
599abb7d134c02ac60091108c491dafb00877093170John Hoford        setAnimationFraction(0);
600abb7d134c02ac60091108c491dafb00877093170John Hoford    }
601abb7d134c02ac60091108c491dafb00877093170John Hoford
602abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
603abb7d134c02ac60091108c491dafb00877093170John Hoford    public boolean setVisible(boolean visible, boolean restart) {
604abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean changed = super.setVisible(visible, restart);
605abb7d134c02ac60091108c491dafb00877093170John Hoford        if (visible) {
606abb7d134c02ac60091108c491dafb00877093170John Hoford            if (changed || restart) {
607abb7d134c02ac60091108c491dafb00877093170John Hoford                setAnimationFraction(0);
608abb7d134c02ac60091108c491dafb00877093170John Hoford            }
609abb7d134c02ac60091108c491dafb00877093170John Hoford        } else {
610abb7d134c02ac60091108c491dafb00877093170John Hoford            stop();
611abb7d134c02ac60091108c491dafb00877093170John Hoford        }
612abb7d134c02ac60091108c491dafb00877093170John Hoford        return changed;
613abb7d134c02ac60091108c491dafb00877093170John Hoford    }
614abb7d134c02ac60091108c491dafb00877093170John Hoford
615abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VAnimatedPath {
616abb7d134c02ac60091108c491dafb00877093170John Hoford        private ArrayList<VAnimation> mCurrentAnimList = null;
617abb7d134c02ac60091108c491dafb00877093170John Hoford        private VPath[] mCurrentPaths;
618abb7d134c02ac60091108c491dafb00877093170John Hoford        private float mAnimationValue = 0; // value goes from 0 to 1
619abb7d134c02ac60091108c491dafb00877093170John Hoford        private Paint mStrokePaint = null;
620abb7d134c02ac60091108c491dafb00877093170John Hoford        private Paint mFillPaint = null;
621abb7d134c02ac60091108c491dafb00877093170John Hoford        private PathMeasure mPathMeasure;
622abb7d134c02ac60091108c491dafb00877093170John Hoford        private Path mPath = new Path();
623abb7d134c02ac60091108c491dafb00877093170John Hoford        private Path mRenderPath = new Path();
624abb7d134c02ac60091108c491dafb00877093170John Hoford        private Matrix mMatrix = new Matrix();
625abb7d134c02ac60091108c491dafb00877093170John Hoford        private long mTotalDuration;
626abb7d134c02ac60091108c491dafb00877093170John Hoford        private int[] mCurrentState = new int[0];
627abb7d134c02ac60091108c491dafb00877093170John Hoford        private int mTrigger;
628abb7d134c02ac60091108c491dafb00877093170John Hoford        private boolean mTriggerState;
6299453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        final ArrayList<VGroup> mGroupList = new ArrayList<VGroup>();
6319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
632abb7d134c02ac60091108c491dafb00877093170John Hoford        float mBaseWidth = 1;
633abb7d134c02ac60091108c491dafb00877093170John Hoford        float mBaseHeight = 1;
634abb7d134c02ac60091108c491dafb00877093170John Hoford        float mViewportWidth;
635abb7d134c02ac60091108c491dafb00877093170John Hoford        float mViewportHeight;
636abb7d134c02ac60091108c491dafb00877093170John Hoford
637abb7d134c02ac60091108c491dafb00877093170John Hoford        public VAnimatedPath() {
638abb7d134c02ac60091108c491dafb00877093170John Hoford            setup();
639abb7d134c02ac60091108c491dafb00877093170John Hoford        }
6409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
641abb7d134c02ac60091108c491dafb00877093170John Hoford        public VAnimatedPath(VAnimatedPath copy) {
642abb7d134c02ac60091108c491dafb00877093170John Hoford            setup();
643abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentAnimList = new ArrayList<VAnimation>(copy.mCurrentAnimList);
6449453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            mGroupList.addAll(copy.mGroupList);
645abb7d134c02ac60091108c491dafb00877093170John Hoford            if (copy.mCurrentPaths != null) {
646abb7d134c02ac60091108c491dafb00877093170John Hoford                mCurrentPaths = new VPath[copy.mCurrentPaths.length];
647abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int i = 0; i < mCurrentPaths.length; i++) {
648abb7d134c02ac60091108c491dafb00877093170John Hoford                    mCurrentPaths[i] = new VPath(copy.mCurrentPaths[i]);
649abb7d134c02ac60091108c491dafb00877093170John Hoford                }
650abb7d134c02ac60091108c491dafb00877093170John Hoford            }
651abb7d134c02ac60091108c491dafb00877093170John Hoford            mAnimationValue = copy.mAnimationValue; // time goes from 0 to 1
652abb7d134c02ac60091108c491dafb00877093170John Hoford
653abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseWidth = copy.mBaseWidth;
654abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseHeight = copy.mBaseHeight;
655abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportWidth = copy.mViewportHeight;
656abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportHeight = copy.mViewportHeight;
657abb7d134c02ac60091108c491dafb00877093170John Hoford            mTotalDuration = copy.mTotalDuration;
658abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrigger = copy.mTrigger;
659abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentState = new int[0];
660abb7d134c02ac60091108c491dafb00877093170John Hoford        }
661abb7d134c02ac60091108c491dafb00877093170John Hoford
6629453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean canApplyTheme() {
6639453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final ArrayList<VGroup> groups = mGroupList;
6649453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            for (int i = groups.size() - 1; i >= 0; i--) {
6659453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final ArrayList<VPath> paths = groups.get(i).mVGList;
6669453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                for (int j = paths.size() - 1; j >= 0; j--) {
6679453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final VPath path = paths.get(j);
6689453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    if (path.canApplyTheme()) {
6699453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                        return true;
6709453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    }
6719453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
6729453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
6739453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6749453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final ArrayList<VAnimation> anims = mCurrentAnimList;
6759453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            for (int i = anims.size() - 1; i >= 0; i--) {
6769453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final VAnimation anim = anims.get(i);
6779453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                if (anim.canApplyTheme()) {
6789453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    return true;
6799453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
6809453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
6819453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6829453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return false;
6839453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
6849453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6859453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void applyTheme(Theme t) {
6869453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final ArrayList<VGroup> groups = mGroupList;
6879453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            for (int i = groups.size() - 1; i >= 0; i--) {
6889453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final ArrayList<VPath> paths = groups.get(i).mVGList;
6899453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                for (int j = paths.size() - 1; j >= 0; j--) {
6909453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final VPath path = paths.get(j);
6919453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    if (path.canApplyTheme()) {
6929453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                        path.applyTheme(t);
6939453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    }
6949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
6959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
6969453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6979453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final ArrayList<VAnimation> anims = mCurrentAnimList;
6989453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            for (int i = anims.size() - 1; i >= 0; i--) {
6999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final VAnimation anim = anims.get(i);
7009453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                if (anim.canApplyTheme()) {
7019453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    anim.applyTheme(t);
7029453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
7039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
7049453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
7059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
706abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setTrigger(int trigger){
7079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int [] lut = {
7089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    0,
709abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.attr.state_pressed,
710abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.attr.state_focused,
711abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.attr.state_hovered,
712abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.attr.state_selected,
713abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.attr.state_checkable,
714abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.attr.state_checked,
715abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.attr.state_activated,
716abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.attr.state_focused
717abb7d134c02ac60091108c491dafb00877093170John Hoford            };
7189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
719abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrigger = lut[trigger];
720abb7d134c02ac60091108c491dafb00877093170John Hoford         }
721abb7d134c02ac60091108c491dafb00877093170John Hoford
722abb7d134c02ac60091108c491dafb00877093170John Hoford        private void setup(){
723abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokePaint = new Paint();
724abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokePaint.setStyle(Paint.Style.STROKE);
725abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokePaint.setAntiAlias(true);
726abb7d134c02ac60091108c491dafb00877093170John Hoford            mFillPaint = new Paint();
727abb7d134c02ac60091108c491dafb00877093170John Hoford            mFillPaint.setStyle(Paint.Style.FILL);
728abb7d134c02ac60091108c491dafb00877093170John Hoford            mFillPaint.setAntiAlias(true);
729abb7d134c02ac60091108c491dafb00877093170John Hoford        }
730abb7d134c02ac60091108c491dafb00877093170John Hoford
731abb7d134c02ac60091108c491dafb00877093170John Hoford        public long getTotalAnimationDuration() {
732abb7d134c02ac60091108c491dafb00877093170John Hoford            mTotalDuration = 0;
733abb7d134c02ac60091108c491dafb00877093170John Hoford            int size = mCurrentAnimList.size();
734abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < size; i++) {
735abb7d134c02ac60091108c491dafb00877093170John Hoford                VAnimation vAnimation = mCurrentAnimList.get(i);
736abb7d134c02ac60091108c491dafb00877093170John Hoford                long t = vAnimation.getTotalDuration();
737abb7d134c02ac60091108c491dafb00877093170John Hoford                if (t == -1) {
738abb7d134c02ac60091108c491dafb00877093170John Hoford                    mTotalDuration = -1;
739abb7d134c02ac60091108c491dafb00877093170John Hoford                    return -1;
740abb7d134c02ac60091108c491dafb00877093170John Hoford                }
741abb7d134c02ac60091108c491dafb00877093170John Hoford                mTotalDuration = Math.max(mTotalDuration, t);
742abb7d134c02ac60091108c491dafb00877093170John Hoford            }
743abb7d134c02ac60091108c491dafb00877093170John Hoford
744abb7d134c02ac60091108c491dafb00877093170John Hoford            return mTotalDuration;
745abb7d134c02ac60091108c491dafb00877093170John Hoford        }
746abb7d134c02ac60091108c491dafb00877093170John Hoford
747abb7d134c02ac60091108c491dafb00877093170John Hoford        public float getValue() {
748abb7d134c02ac60091108c491dafb00877093170John Hoford            return mAnimationValue;
749abb7d134c02ac60091108c491dafb00877093170John Hoford        }
750abb7d134c02ac60091108c491dafb00877093170John Hoford
751abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
752abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param value the point along the animations to show typically between 0.0f and 1.0f
753abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return true if you need to keep repeating
754abb7d134c02ac60091108c491dafb00877093170John Hoford         */
755abb7d134c02ac60091108c491dafb00877093170John Hoford        public boolean setAnimationFraction(float value) {
756abb7d134c02ac60091108c491dafb00877093170John Hoford            getTotalAnimationDuration();
7579453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
758abb7d134c02ac60091108c491dafb00877093170John Hoford            long animationTime = (long) (value * mTotalDuration);
759abb7d134c02ac60091108c491dafb00877093170John Hoford
7609453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int len = mCurrentPaths.length;
761abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < len; i++) {
762abb7d134c02ac60091108c491dafb00877093170John Hoford                animationTime =
763abb7d134c02ac60091108c491dafb00877093170John Hoford                        (long) ((mTotalDuration == -1) ? value * 1000 : mTotalDuration * value);
7649453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7659453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final VPath path = mCurrentPaths[i];
7669453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final int size = mCurrentAnimList.size();
767abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int j = 0; j < size; j++) {
7689453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final VAnimation vAnimation = mCurrentAnimList.get(j);
769abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (vAnimation.doesAdjustPath(path)) {
770abb7d134c02ac60091108c491dafb00877093170John Hoford                        mCurrentPaths[i] =  vAnimation.getPathAtTime(animationTime, path);
771abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
772abb7d134c02ac60091108c491dafb00877093170John Hoford                }
773abb7d134c02ac60091108c491dafb00877093170John Hoford            }
7749453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7759453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            mAnimationValue = value;
7769453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
777abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mTotalDuration == -1) {
778abb7d134c02ac60091108c491dafb00877093170John Hoford                return true;
779abb7d134c02ac60091108c491dafb00877093170John Hoford            } else {
780abb7d134c02ac60091108c491dafb00877093170John Hoford                return animationTime < mTotalDuration;
781abb7d134c02ac60091108c491dafb00877093170John Hoford            }
782abb7d134c02ac60091108c491dafb00877093170John Hoford        }
783abb7d134c02ac60091108c491dafb00877093170John Hoford
784abb7d134c02ac60091108c491dafb00877093170John Hoford        public void draw(Canvas canvas) {
785abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mCurrentPaths == null) {
786abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.e(LOGTAG,"mCurrentPaths == null");
787abb7d134c02ac60091108c491dafb00877093170John Hoford                return;
788abb7d134c02ac60091108c491dafb00877093170John Hoford            }
789abb7d134c02ac60091108c491dafb00877093170John Hoford
7909453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            // TODO: This should probably use getBounds().
7919453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int w = canvas.getWidth();
7929453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int h = canvas.getHeight();
7939453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
794abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mCurrentPaths.length; i++) {
795abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mCurrentPaths[i] != null && mCurrentPaths[i].isVisible(mCurrentState)) {
796abb7d134c02ac60091108c491dafb00877093170John Hoford                    drawPath(mCurrentPaths[i], canvas, w, h);
797abb7d134c02ac60091108c491dafb00877093170John Hoford                }
798abb7d134c02ac60091108c491dafb00877093170John Hoford            }
799abb7d134c02ac60091108c491dafb00877093170John Hoford        }
800abb7d134c02ac60091108c491dafb00877093170John Hoford
801abb7d134c02ac60091108c491dafb00877093170John Hoford        private void drawPath(VPath vPath, Canvas canvas, int w, int h) {
8029453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final float scale = Math.min(h / mViewportHeight, w / mViewportWidth);
803abb7d134c02ac60091108c491dafb00877093170John Hoford
804abb7d134c02ac60091108c491dafb00877093170John Hoford            vPath.toPath(mPath);
805abb7d134c02ac60091108c491dafb00877093170John Hoford            Path path = mPath;
806abb7d134c02ac60091108c491dafb00877093170John Hoford
807abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mTrimPathStart != 0.0f || vPath.mTrimPathEnd != 1.0f) {
808abb7d134c02ac60091108c491dafb00877093170John Hoford                float start = (vPath.mTrimPathStart + vPath.mTrimPathOffset) % 1.0f;
809abb7d134c02ac60091108c491dafb00877093170John Hoford                float end = (vPath.mTrimPathEnd + vPath.mTrimPathOffset) % 1.0f;
810abb7d134c02ac60091108c491dafb00877093170John Hoford
811abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPathMeasure == null) {
812abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure = new PathMeasure();
813abb7d134c02ac60091108c491dafb00877093170John Hoford                }
814abb7d134c02ac60091108c491dafb00877093170John Hoford                mPathMeasure.setPath(mPath, false);
815abb7d134c02ac60091108c491dafb00877093170John Hoford
816abb7d134c02ac60091108c491dafb00877093170John Hoford                float len = mPathMeasure.getLength();
817abb7d134c02ac60091108c491dafb00877093170John Hoford                start = start * len;
818abb7d134c02ac60091108c491dafb00877093170John Hoford                end = end * len;
819abb7d134c02ac60091108c491dafb00877093170John Hoford                path.reset();
820abb7d134c02ac60091108c491dafb00877093170John Hoford                if (start > end) {
821abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure.getSegment(start, len, path, true);
822abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure.getSegment(0f, end, path, true);
823abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
824abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure.getSegment(start, end, path, true);
825abb7d134c02ac60091108c491dafb00877093170John Hoford                }
826abb7d134c02ac60091108c491dafb00877093170John Hoford                path.rLineTo(0, 0); // fix bug in measure
827abb7d134c02ac60091108c491dafb00877093170John Hoford            }
828abb7d134c02ac60091108c491dafb00877093170John Hoford
829abb7d134c02ac60091108c491dafb00877093170John Hoford            mRenderPath.reset();
830abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.reset();
831abb7d134c02ac60091108c491dafb00877093170John Hoford
832abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.postRotate(vPath.mRotate, vPath.mPivotX, vPath.mPivotY);
833abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.postScale(scale, scale, mViewportWidth / 2f, mViewportHeight / 2f);
834abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.postTranslate(w / 2f - mViewportWidth / 2f, h / 2f - mViewportHeight / 2f);
835abb7d134c02ac60091108c491dafb00877093170John Hoford
836abb7d134c02ac60091108c491dafb00877093170John Hoford            mRenderPath.addPath(path, mMatrix);
837abb7d134c02ac60091108c491dafb00877093170John Hoford
838abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mClip) {
839abb7d134c02ac60091108c491dafb00877093170John Hoford                canvas.clipPath(mRenderPath, Region.Op.REPLACE);
840abb7d134c02ac60091108c491dafb00877093170John Hoford            }
8419453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
842abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mFillColor != 0) {
843abb7d134c02ac60091108c491dafb00877093170John Hoford                mFillPaint.setColor(vPath.mFillColor);
844abb7d134c02ac60091108c491dafb00877093170John Hoford                int alpha = 0xFF & (vPath.mFillColor >> 24);
845abb7d134c02ac60091108c491dafb00877093170John Hoford                mFillPaint.setAlpha(alpha);
846abb7d134c02ac60091108c491dafb00877093170John Hoford                canvas.drawPath(mRenderPath, mFillPaint);
847abb7d134c02ac60091108c491dafb00877093170John Hoford            }
8489453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
849abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mStrokeColor != 0) {
850abb7d134c02ac60091108c491dafb00877093170John Hoford                if (vPath.mStrokelineJoin != null) {
851abb7d134c02ac60091108c491dafb00877093170John Hoford                    mStrokePaint.setStrokeJoin(vPath.mStrokelineJoin);
852abb7d134c02ac60091108c491dafb00877093170John Hoford                }
853abb7d134c02ac60091108c491dafb00877093170John Hoford                if (vPath.mStrokelineCap != null) {
854abb7d134c02ac60091108c491dafb00877093170John Hoford                    mStrokePaint.setStrokeCap(vPath.mStrokelineCap);
855abb7d134c02ac60091108c491dafb00877093170John Hoford                }
856abb7d134c02ac60091108c491dafb00877093170John Hoford                mStrokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale);
857abb7d134c02ac60091108c491dafb00877093170John Hoford                mStrokePaint.setColor(vPath.mStrokeColor);
858abb7d134c02ac60091108c491dafb00877093170John Hoford                mStrokePaint.setAlpha(0xFF & (vPath.mStrokeColor >> 24));
859abb7d134c02ac60091108c491dafb00877093170John Hoford                mStrokePaint.setStrokeWidth(vPath.mStrokeWidth * scale);
860abb7d134c02ac60091108c491dafb00877093170John Hoford                canvas.drawPath(mRenderPath, mStrokePaint);
861abb7d134c02ac60091108c491dafb00877093170John Hoford            }
862abb7d134c02ac60091108c491dafb00877093170John Hoford        }
863abb7d134c02ac60091108c491dafb00877093170John Hoford
864abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
865abb7d134c02ac60091108c491dafb00877093170John Hoford         * Ensure there is at least one animation for every path in group (linking them by names)
866abb7d134c02ac60091108c491dafb00877093170John Hoford         * Build the "current" path based on the first group
867abb7d134c02ac60091108c491dafb00877093170John Hoford         * TODO: improve memory use & performance or move to C++
868abb7d134c02ac60091108c491dafb00877093170John Hoford         */
869abb7d134c02ac60091108c491dafb00877093170John Hoford        public void parseFinish() {
8709453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final HashMap<String, VAnimation> newAnimations = new HashMap<String, VAnimation>();
871abb7d134c02ac60091108c491dafb00877093170John Hoford            for (VGroup group : mGroupList) {
872abb7d134c02ac60091108c491dafb00877093170John Hoford                for (VPath vPath : group.getPaths()) {
873abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (!vPath.mAnimated) {
874abb7d134c02ac60091108c491dafb00877093170John Hoford                        VAnimation ap = null;
875abb7d134c02ac60091108c491dafb00877093170John Hoford
876abb7d134c02ac60091108c491dafb00877093170John Hoford                        if (!newAnimations.containsKey(vPath.getID())) {
877abb7d134c02ac60091108c491dafb00877093170John Hoford                            newAnimations.put(vPath.getID(), ap = new VAnimation());
878abb7d134c02ac60091108c491dafb00877093170John Hoford                        } else {
879abb7d134c02ac60091108c491dafb00877093170John Hoford                            ap = newAnimations.get(vPath.getID());
880abb7d134c02ac60091108c491dafb00877093170John Hoford                        }
8819453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
882abb7d134c02ac60091108c491dafb00877093170John Hoford                        ap.addPath(vPath);
883abb7d134c02ac60091108c491dafb00877093170John Hoford                        vPath.mAnimated = true;
884abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
885abb7d134c02ac60091108c491dafb00877093170John Hoford                }
886abb7d134c02ac60091108c491dafb00877093170John Hoford            }
8879453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
888abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mCurrentAnimList == null) {
889abb7d134c02ac60091108c491dafb00877093170John Hoford                mCurrentAnimList = new ArrayList<VectorDrawable.VAnimation>();
890abb7d134c02ac60091108c491dafb00877093170John Hoford            }
891abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentAnimList.addAll(newAnimations.values());
8929453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
8939453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final Collection<VPath> paths = mGroupList.get(0).getPaths();
894abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentPaths = paths.toArray(new VPath[paths.size()]);
895abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mCurrentPaths.length; i++) {
896abb7d134c02ac60091108c491dafb00877093170John Hoford                mCurrentPaths[i] = new VPath(mCurrentPaths[i]);
897abb7d134c02ac60091108c491dafb00877093170John Hoford            }
898abb7d134c02ac60091108c491dafb00877093170John Hoford        }
899abb7d134c02ac60091108c491dafb00877093170John Hoford
900abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setState(int[] state) {
901abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentState = Arrays.copyOf(state, state.length);
902abb7d134c02ac60091108c491dafb00877093170John Hoford        }
903abb7d134c02ac60091108c491dafb00877093170John Hoford
904abb7d134c02ac60091108c491dafb00877093170John Hoford        int getTrigger(int []state){
905abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mTrigger == 0) return 0;
906abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < state.length; i++) {
907abb7d134c02ac60091108c491dafb00877093170John Hoford                if (state[i] == mTrigger){
908abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (mTriggerState)
909abb7d134c02ac60091108c491dafb00877093170John Hoford                        return 0;
910abb7d134c02ac60091108c491dafb00877093170John Hoford                    mTriggerState = true;
911abb7d134c02ac60091108c491dafb00877093170John Hoford                    return 1;
912abb7d134c02ac60091108c491dafb00877093170John Hoford                }
913abb7d134c02ac60091108c491dafb00877093170John Hoford            }
914abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mTriggerState) {
915abb7d134c02ac60091108c491dafb00877093170John Hoford                mTriggerState = false;
916abb7d134c02ac60091108c491dafb00877093170John Hoford                return -1;
917abb7d134c02ac60091108c491dafb00877093170John Hoford            }
918abb7d134c02ac60091108c491dafb00877093170John Hoford            return 0;
919abb7d134c02ac60091108c491dafb00877093170John Hoford        }
920abb7d134c02ac60091108c491dafb00877093170John Hoford
921abb7d134c02ac60091108c491dafb00877093170John Hoford        public void addAnimation(VAnimation anim) {
922abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mCurrentAnimList == null) {
923abb7d134c02ac60091108c491dafb00877093170John Hoford                mCurrentAnimList = new ArrayList<VectorDrawable.VAnimation>();
924abb7d134c02ac60091108c491dafb00877093170John Hoford            }
925abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentAnimList.add(anim);
926abb7d134c02ac60091108c491dafb00877093170John Hoford        }
927abb7d134c02ac60091108c491dafb00877093170John Hoford
928abb7d134c02ac60091108c491dafb00877093170John Hoford        private void parseViewport(Resources r, AttributeSet attrs)
929abb7d134c02ac60091108c491dafb00877093170John Hoford                throws XmlPullParserException {
930abb7d134c02ac60091108c491dafb00877093170John Hoford            TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport);
931abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportWidth = a.getFloat(R.styleable.VectorDrawableViewport_viewportWidth, 0);
932abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportHeight = a.getFloat(R.styleable.VectorDrawableViewport_viewportHeight, 0);
933abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mViewportWidth == 0 || mViewportHeight == 0) {
934abb7d134c02ac60091108c491dafb00877093170John Hoford                throw new XmlPullParserException(a.getPositionDescription()+
935abb7d134c02ac60091108c491dafb00877093170John Hoford                        "<viewport> tag requires viewportWidth & viewportHeight to be set");
936abb7d134c02ac60091108c491dafb00877093170John Hoford            }
937abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
938abb7d134c02ac60091108c491dafb00877093170John Hoford        }
939abb7d134c02ac60091108c491dafb00877093170John Hoford
940abb7d134c02ac60091108c491dafb00877093170John Hoford        private void parseSize(Resources r, AttributeSet attrs)
941abb7d134c02ac60091108c491dafb00877093170John Hoford                throws XmlPullParserException  {
942abb7d134c02ac60091108c491dafb00877093170John Hoford            TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableSize);
943abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseWidth = a.getDimension(R.styleable.VectorDrawableSize_width, 0);
944abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseHeight = a.getDimension(R.styleable.VectorDrawableSize_height, 0);
945abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mBaseWidth == 0 || mBaseHeight == 0) {
946abb7d134c02ac60091108c491dafb00877093170John Hoford                throw new XmlPullParserException(a.getPositionDescription()+
947abb7d134c02ac60091108c491dafb00877093170John Hoford                        "<size> tag requires width & height to be set");
948abb7d134c02ac60091108c491dafb00877093170John Hoford            }
949abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
950abb7d134c02ac60091108c491dafb00877093170John Hoford        }
951abb7d134c02ac60091108c491dafb00877093170John Hoford    }
952abb7d134c02ac60091108c491dafb00877093170John Hoford
953abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VAnimation {
9549453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private final static int DIRECTION_FORWARD = 0;
9559453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private final static int DIRECTION_IN_AND_OUT = 1;
9569453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
957abb7d134c02ac60091108c491dafb00877093170John Hoford        private VPath[] mPaths = new VPath[0];
958abb7d134c02ac60091108c491dafb00877093170John Hoford
959abb7d134c02ac60091108c491dafb00877093170John Hoford        public enum Style {
960abb7d134c02ac60091108c491dafb00877093170John Hoford            INTERPOLATE, CROSSFADE, WIPE
961abb7d134c02ac60091108c491dafb00877093170John Hoford        }
9629453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
963abb7d134c02ac60091108c491dafb00877093170John Hoford        Interpolator mAnimInterpolator = new AccelerateDecelerateInterpolator();
9649453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
9659453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private int[] mThemeAttrs;
966abb7d134c02ac60091108c491dafb00877093170John Hoford        private Style mStyle;
967abb7d134c02ac60091108c491dafb00877093170John Hoford        private int mLimitProperty = 0;
968abb7d134c02ac60091108c491dafb00877093170John Hoford        private long[] mDuration = {DEFAULT_DURATION};
969abb7d134c02ac60091108c491dafb00877093170John Hoford        private long mStartOffset;
970abb7d134c02ac60091108c491dafb00877093170John Hoford        private long mRepeat = 1;
9719453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private HashSet<String> mSeqMap = new HashSet<String>();
972abb7d134c02ac60091108c491dafb00877093170John Hoford        private long mWipeDirection;
973abb7d134c02ac60091108c491dafb00877093170John Hoford        private int mMode = 0; // forward = 0 inAndOut = 1;
974abb7d134c02ac60091108c491dafb00877093170John Hoford        private int mInterpolatorType;
975abb7d134c02ac60091108c491dafb00877093170John Hoford        private String mId;
976abb7d134c02ac60091108c491dafb00877093170John Hoford
977abb7d134c02ac60091108c491dafb00877093170John Hoford        public VAnimation() {
9789453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            // Empty constructor.
979abb7d134c02ac60091108c491dafb00877093170John Hoford        }
980abb7d134c02ac60091108c491dafb00877093170John Hoford
9819453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void inflate(ArrayList<VGroup> groups, Resources r, AttributeSet attrs, Theme theme)
982abb7d134c02ac60091108c491dafb00877093170John Hoford                throws XmlPullParserException {
983abb7d134c02ac60091108c491dafb00877093170John Hoford            String value;
984abb7d134c02ac60091108c491dafb00877093170John Hoford            String[] sp;
985abb7d134c02ac60091108c491dafb00877093170John Hoford            int name;
986abb7d134c02ac60091108c491dafb00877093170John Hoford
9879453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableAnimation);
9889453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            mThemeAttrs = a.extractThemeAttrs();
989abb7d134c02ac60091108c491dafb00877093170John Hoford
990abb7d134c02ac60091108c491dafb00877093170John Hoford            value = a.getString(R.styleable.VectorDrawableAnimation_sequence);
991abb7d134c02ac60091108c491dafb00877093170John Hoford            if (value != null) {
992abb7d134c02ac60091108c491dafb00877093170John Hoford                sp = value.split(",");
993abb7d134c02ac60091108c491dafb00877093170John Hoford                VectorDrawable.VPath[] paths = new VectorDrawable.VPath[sp.length];
994abb7d134c02ac60091108c491dafb00877093170John Hoford
995abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int j = 0; j < sp.length; j++) {
996abb7d134c02ac60091108c491dafb00877093170John Hoford                    mSeqMap.add(sp[j].trim());
997abb7d134c02ac60091108c491dafb00877093170John Hoford                    VectorDrawable.VPath path = groups.get(j).get(sp[j]);
998abb7d134c02ac60091108c491dafb00877093170John Hoford                    path.mAnimated = true;
999abb7d134c02ac60091108c491dafb00877093170John Hoford                    paths[j] = path;
1000abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1001abb7d134c02ac60091108c491dafb00877093170John Hoford                setPaths(paths);
1002abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1003abb7d134c02ac60091108c491dafb00877093170John Hoford
1004abb7d134c02ac60091108c491dafb00877093170John Hoford            setLimitProperty(a.getInt(R.styleable.VectorDrawableAnimation_limitTo, 0));
1005abb7d134c02ac60091108c491dafb00877093170John Hoford
1006abb7d134c02ac60091108c491dafb00877093170John Hoford            name = R.styleable.VectorDrawableAnimation_durations;
1007abb7d134c02ac60091108c491dafb00877093170John Hoford            value = a.getString(name);
1008abb7d134c02ac60091108c491dafb00877093170John Hoford            if (value != null) {
1009abb7d134c02ac60091108c491dafb00877093170John Hoford                long totalDuration = 0;
1010abb7d134c02ac60091108c491dafb00877093170John Hoford                sp = value.split(",");
10119453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
10129453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final long[] dur = new long[sp.length];
1013abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int j = 0; j < dur.length; j++) {
1014abb7d134c02ac60091108c491dafb00877093170John Hoford                    dur[j] = Long.parseLong(sp[j]);
1015abb7d134c02ac60091108c491dafb00877093170John Hoford                    totalDuration +=  dur[j];
1016abb7d134c02ac60091108c491dafb00877093170John Hoford                }
10179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1018abb7d134c02ac60091108c491dafb00877093170John Hoford                if (totalDuration == 0){
1019abb7d134c02ac60091108c491dafb00877093170John Hoford                    throw new XmlPullParserException(a.getPositionDescription()+
1020abb7d134c02ac60091108c491dafb00877093170John Hoford                            "total duration must not be zero");
1021abb7d134c02ac60091108c491dafb00877093170John Hoford                }
10229453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1023abb7d134c02ac60091108c491dafb00877093170John Hoford                setDuration(dur);
1024abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1025abb7d134c02ac60091108c491dafb00877093170John Hoford
1026abb7d134c02ac60091108c491dafb00877093170John Hoford            setRepeat(a.getInt(R.styleable.VectorDrawableAnimation_repeatCount, 1));
1027abb7d134c02ac60091108c491dafb00877093170John Hoford            setStartOffset(a.getInt(R.styleable.VectorDrawableAnimation_startDelay, 0));
1028abb7d134c02ac60091108c491dafb00877093170John Hoford            setMode(a.getInt(R.styleable.VectorDrawableAnimation_repeatStyle, 0));
1029abb7d134c02ac60091108c491dafb00877093170John Hoford
1030abb7d134c02ac60091108c491dafb00877093170John Hoford            fixMissingParameters();
10319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1032abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
1033abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1034abb7d134c02ac60091108c491dafb00877093170John Hoford
10359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean canApplyTheme() {
10369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return mThemeAttrs != null;
10379453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
10389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
10399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void applyTheme(Theme t) {
10409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            // TODO: Apply theme.
10419453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
10429453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
10439453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean doesAdjustPath(VPath path) {
10449453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return mSeqMap.contains(path.getID());
10459453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
10469453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1047abb7d134c02ac60091108c491dafb00877093170John Hoford        public String getId() {
1048abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mId == null) {
1049abb7d134c02ac60091108c491dafb00877093170John Hoford                mId = mPaths[0].getID();
1050abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int i = 1; i < mPaths.length; i++) {
1051abb7d134c02ac60091108c491dafb00877093170John Hoford                    mId += mPaths[i].getID();
1052abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1053abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1054abb7d134c02ac60091108c491dafb00877093170John Hoford            return mId;
1055abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1056abb7d134c02ac60091108c491dafb00877093170John Hoford
1057abb7d134c02ac60091108c491dafb00877093170John Hoford        public String getPathName() {
1058abb7d134c02ac60091108c491dafb00877093170John Hoford            return mPaths[0].getID();
1059abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1060abb7d134c02ac60091108c491dafb00877093170John Hoford
1061abb7d134c02ac60091108c491dafb00877093170John Hoford        public Style getStyle() {
1062abb7d134c02ac60091108c491dafb00877093170John Hoford            return mStyle;
1063abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1064abb7d134c02ac60091108c491dafb00877093170John Hoford
1065abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setStyle(Style style) {
1066abb7d134c02ac60091108c491dafb00877093170John Hoford            this.mStyle = style;
1067abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1068abb7d134c02ac60091108c491dafb00877093170John Hoford
1069abb7d134c02ac60091108c491dafb00877093170John Hoford        public int getLimitProperty() {
1070abb7d134c02ac60091108c491dafb00877093170John Hoford            return mLimitProperty;
1071abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1072abb7d134c02ac60091108c491dafb00877093170John Hoford
1073abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setLimitProperty(int limitProperty) {
1074abb7d134c02ac60091108c491dafb00877093170John Hoford            this.mLimitProperty = limitProperty;
1075abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1076abb7d134c02ac60091108c491dafb00877093170John Hoford
1077abb7d134c02ac60091108c491dafb00877093170John Hoford        public long[] getDuration() {
1078abb7d134c02ac60091108c491dafb00877093170John Hoford            return mDuration;
1079abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1080abb7d134c02ac60091108c491dafb00877093170John Hoford
1081abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setDuration(long[] duration) {
1082abb7d134c02ac60091108c491dafb00877093170John Hoford            this.mDuration = duration;
1083abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1084abb7d134c02ac60091108c491dafb00877093170John Hoford
1085abb7d134c02ac60091108c491dafb00877093170John Hoford        public long getRepeat() {
1086abb7d134c02ac60091108c491dafb00877093170John Hoford            return mRepeat;
1087abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1088abb7d134c02ac60091108c491dafb00877093170John Hoford
1089abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setRepeat(long repeat) {
1090abb7d134c02ac60091108c491dafb00877093170John Hoford            this.mRepeat = repeat;
1091abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1092abb7d134c02ac60091108c491dafb00877093170John Hoford
1093abb7d134c02ac60091108c491dafb00877093170John Hoford        public long getStartOffset() {
1094abb7d134c02ac60091108c491dafb00877093170John Hoford            return mStartOffset;
1095abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1096abb7d134c02ac60091108c491dafb00877093170John Hoford
1097abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setStartOffset(long startOffset) {
1098abb7d134c02ac60091108c491dafb00877093170John Hoford            this.mStartOffset = startOffset;
1099abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1100abb7d134c02ac60091108c491dafb00877093170John Hoford
1101abb7d134c02ac60091108c491dafb00877093170John Hoford        public long getWipeDirection() {
1102abb7d134c02ac60091108c491dafb00877093170John Hoford            return mWipeDirection;
1103abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1104abb7d134c02ac60091108c491dafb00877093170John Hoford
1105abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setWipeDirection(long wipeDirection) {
1106abb7d134c02ac60091108c491dafb00877093170John Hoford            this.mWipeDirection = wipeDirection;
1107abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1108abb7d134c02ac60091108c491dafb00877093170John Hoford
1109abb7d134c02ac60091108c491dafb00877093170John Hoford        public int getMode() {
1110abb7d134c02ac60091108c491dafb00877093170John Hoford            return mMode;
1111abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1112abb7d134c02ac60091108c491dafb00877093170John Hoford
1113abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setMode(int mode) {
1114abb7d134c02ac60091108c491dafb00877093170John Hoford            this.mMode = mode;
1115abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1116abb7d134c02ac60091108c491dafb00877093170John Hoford
1117abb7d134c02ac60091108c491dafb00877093170John Hoford        public int getInterpolator() {
1118abb7d134c02ac60091108c491dafb00877093170John Hoford            return mInterpolatorType;
1119abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1120abb7d134c02ac60091108c491dafb00877093170John Hoford
1121abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setInterpolator(int interpolator) {
1122abb7d134c02ac60091108c491dafb00877093170John Hoford            this.mInterpolatorType = interpolator;
1123abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1124abb7d134c02ac60091108c491dafb00877093170John Hoford
1125abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1126abb7d134c02ac60091108c491dafb00877093170John Hoford         * compute the total time in milliseconds
1127abb7d134c02ac60091108c491dafb00877093170John Hoford         *
1128abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return the total time in milliseconds the animation will take
1129abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1130abb7d134c02ac60091108c491dafb00877093170John Hoford        public long getTotalDuration() {
1131abb7d134c02ac60091108c491dafb00877093170John Hoford            long total = mStartOffset;
1132abb7d134c02ac60091108c491dafb00877093170John Hoford            if (getRepeat() == -1) {
1133abb7d134c02ac60091108c491dafb00877093170John Hoford                return -1;
1134abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1135abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mDuration.length; i++) {
1136abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mRepeat > 1) {
1137abb7d134c02ac60091108c491dafb00877093170John Hoford                    total += mDuration[i] * mRepeat;
1138abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
1139abb7d134c02ac60091108c491dafb00877093170John Hoford                    total += mDuration[i];
1140abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1141abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1142abb7d134c02ac60091108c491dafb00877093170John Hoford            return total;
1143abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1144abb7d134c02ac60091108c491dafb00877093170John Hoford
1145abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setPaths(VPath[] paths) {
11469453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            mPaths = paths;
1147abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1148abb7d134c02ac60091108c491dafb00877093170John Hoford
1149abb7d134c02ac60091108c491dafb00877093170John Hoford        public void addPath(VPath path) {
1150abb7d134c02ac60091108c491dafb00877093170John Hoford            mPaths = Arrays.copyOf(mPaths, mPaths.length + 1);
1151abb7d134c02ac60091108c491dafb00877093170John Hoford            mPaths[mPaths.length - 1] = path;
1152abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1153abb7d134c02ac60091108c491dafb00877093170John Hoford
1154abb7d134c02ac60091108c491dafb00877093170John Hoford        public boolean containsPath(String pathid) {
1155abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mPaths.length; i++) {
1156abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPaths[i].getID().equals(pathid)) {
1157abb7d134c02ac60091108c491dafb00877093170John Hoford                    return true;
1158abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1159abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1160abb7d134c02ac60091108c491dafb00877093170John Hoford            return false;
1161abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1162abb7d134c02ac60091108c491dafb00877093170John Hoford
1163abb7d134c02ac60091108c491dafb00877093170John Hoford        public void interpolate(VPath p1, VPath p2, float time, VPath dest) {
11649453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            VPath.interpolate(time, p1, p2, dest, mLimitProperty);
1165abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1166abb7d134c02ac60091108c491dafb00877093170John Hoford
1167abb7d134c02ac60091108c491dafb00877093170John Hoford        public VPath getPathAtTime(long milliseconds, VPath dest) {
1168abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mPaths.length == 1) {
1169abb7d134c02ac60091108c491dafb00877093170John Hoford                dest.copyFrom(mPaths[0]);
1170abb7d134c02ac60091108c491dafb00877093170John Hoford                return dest;
1171abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1172abb7d134c02ac60091108c491dafb00877093170John Hoford            long point = milliseconds - mStartOffset;
1173abb7d134c02ac60091108c491dafb00877093170John Hoford            if (point < 0) {
1174abb7d134c02ac60091108c491dafb00877093170John Hoford                point = 0;
1175abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1176abb7d134c02ac60091108c491dafb00877093170John Hoford            float time = 0;
1177abb7d134c02ac60091108c491dafb00877093170John Hoford            long sum = mDuration[0];
1178abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 1; i < mDuration.length; i++) {
1179abb7d134c02ac60091108c491dafb00877093170John Hoford                sum += mDuration[i];
1180abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1181abb7d134c02ac60091108c491dafb00877093170John Hoford
1182abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mRepeat > 1) {
1183abb7d134c02ac60091108c491dafb00877093170John Hoford                time = point / (float) (sum * mRepeat);
1184abb7d134c02ac60091108c491dafb00877093170John Hoford                time = mAnimInterpolator.getInterpolation(time);
1185abb7d134c02ac60091108c491dafb00877093170John Hoford
1186abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mMode == DIRECTION_IN_AND_OUT) {
1187abb7d134c02ac60091108c491dafb00877093170John Hoford                    point = ((long) (time * sum * 2 * mRepeat)) % (sum * 2);
1188abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (point > sum) {
1189abb7d134c02ac60091108c491dafb00877093170John Hoford                        point = sum * 2 - point;
1190abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1191abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
1192abb7d134c02ac60091108c491dafb00877093170John Hoford                    point = ((long) (time * sum * mRepeat)) % sum;
1193abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1194abb7d134c02ac60091108c491dafb00877093170John Hoford            } else if (mRepeat == 1) {
1195abb7d134c02ac60091108c491dafb00877093170John Hoford                time = point / (float) (sum * mRepeat);
1196abb7d134c02ac60091108c491dafb00877093170John Hoford                time = mAnimInterpolator.getInterpolation(time);
1197abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mMode == DIRECTION_IN_AND_OUT) {
1198abb7d134c02ac60091108c491dafb00877093170John Hoford                    point = ((long) (time * sum * 2 * mRepeat));
1199abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (point > sum) {
1200abb7d134c02ac60091108c491dafb00877093170John Hoford                        point = sum * 2 - point;
1201abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1202abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
1203abb7d134c02ac60091108c491dafb00877093170John Hoford                    point = Math.min(((long) (time * sum * mRepeat)), sum);
1204abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1205abb7d134c02ac60091108c491dafb00877093170John Hoford
1206abb7d134c02ac60091108c491dafb00877093170John Hoford            } else { // repeat = -1
1207abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mMode == DIRECTION_IN_AND_OUT) {
1208abb7d134c02ac60091108c491dafb00877093170John Hoford                    point = point % (sum * 2);
1209abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (point > sum) {
1210abb7d134c02ac60091108c491dafb00877093170John Hoford                        point = sum * 2 - point;
1211abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1212abb7d134c02ac60091108c491dafb00877093170John Hoford                    time = point / (float) sum;
1213abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
1214abb7d134c02ac60091108c491dafb00877093170John Hoford                    point = point % sum;
1215abb7d134c02ac60091108c491dafb00877093170John Hoford                    time = point / (float) sum;
1216abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1217abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1218abb7d134c02ac60091108c491dafb00877093170John Hoford
1219abb7d134c02ac60091108c491dafb00877093170John Hoford            int transition = 0;
1220abb7d134c02ac60091108c491dafb00877093170John Hoford            while (point > mDuration[transition]) {
1221abb7d134c02ac60091108c491dafb00877093170John Hoford                point -= mDuration[transition++];
1222abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1223abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mPaths.length > (transition + 1)) {
1224abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPaths[transition].getID() != dest.getID()) {
1225abb7d134c02ac60091108c491dafb00877093170John Hoford                    dest.copyFrom(mPaths[transition]);
1226abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1227abb7d134c02ac60091108c491dafb00877093170John Hoford                interpolate(mPaths[transition], mPaths[transition + 1],
1228abb7d134c02ac60091108c491dafb00877093170John Hoford                        point / (float) mDuration[transition], dest);
1229abb7d134c02ac60091108c491dafb00877093170John Hoford            } else {
1230abb7d134c02ac60091108c491dafb00877093170John Hoford                interpolate(mPaths[transition], mPaths[transition], 0, dest);
1231abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1232abb7d134c02ac60091108c491dafb00877093170John Hoford            return dest;
1233abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1234abb7d134c02ac60091108c491dafb00877093170John Hoford
1235abb7d134c02ac60091108c491dafb00877093170John Hoford        void fixMissingParameters() {
1236abb7d134c02ac60091108c491dafb00877093170John Hoford            // fix missing points
1237abb7d134c02ac60091108c491dafb00877093170John Hoford            float rotation = Float.NaN;
1238abb7d134c02ac60091108c491dafb00877093170John Hoford            float rotationY = Float.NaN;
1239abb7d134c02ac60091108c491dafb00877093170John Hoford            float rotationX = Float.NaN;
1240abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mPaths.length; i++) {
1241abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPaths[i].mPivotX > 0) {
1242abb7d134c02ac60091108c491dafb00877093170John Hoford                    rotationX = mPaths[i].mPivotX;
1243abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1244abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPaths[i].mPivotY > 0) {
1245abb7d134c02ac60091108c491dafb00877093170John Hoford                    rotationY = mPaths[i].mPivotY;
1246abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1247abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPaths[i].mRotate > 0) {
1248abb7d134c02ac60091108c491dafb00877093170John Hoford                    rotation = mPaths[i].mRotate;
1249abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1250abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1251abb7d134c02ac60091108c491dafb00877093170John Hoford            if (rotation > 0) {
1252abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int i = 0; i < mPaths.length; i++) {
1253abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (mPaths[i].mPivotX == 0) {
1254abb7d134c02ac60091108c491dafb00877093170John Hoford                        mPaths[i].mPivotX = rotationX;
1255abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1256abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (mPaths[i].mPivotY == 0) {
1257abb7d134c02ac60091108c491dafb00877093170John Hoford                        mPaths[i].mPivotY = rotationY;
1258abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1259abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1260abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1261abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1262abb7d134c02ac60091108c491dafb00877093170John Hoford    }
1263abb7d134c02ac60091108c491dafb00877093170John Hoford
1264abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VGroup {
12659453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private final HashMap<String, VPath> mVGPathMap = new HashMap<String, VPath>();
12669453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private final ArrayList<VPath> mVGList = new ArrayList<VPath>();
1267abb7d134c02ac60091108c491dafb00877093170John Hoford
1268abb7d134c02ac60091108c491dafb00877093170John Hoford        public void add(VPath path) {
1269abb7d134c02ac60091108c491dafb00877093170John Hoford            String id = path.getID();
1270abb7d134c02ac60091108c491dafb00877093170John Hoford            mVGPathMap.put(id, path);
1271abb7d134c02ac60091108c491dafb00877093170John Hoford            mVGList.add(path);
1272abb7d134c02ac60091108c491dafb00877093170John Hoford         }
1273abb7d134c02ac60091108c491dafb00877093170John Hoford
1274abb7d134c02ac60091108c491dafb00877093170John Hoford        public VPath get(String name) {
1275abb7d134c02ac60091108c491dafb00877093170John Hoford            return mVGPathMap.get(name);
1276abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1277abb7d134c02ac60091108c491dafb00877093170John Hoford
1278abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1279abb7d134c02ac60091108c491dafb00877093170John Hoford         * Must return in order of adding
1280abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return ordered list of paths
1281abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1282abb7d134c02ac60091108c491dafb00877093170John Hoford        public Collection<VPath> getPaths() {
1283abb7d134c02ac60091108c491dafb00877093170John Hoford            return mVGList;
1284abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1285abb7d134c02ac60091108c491dafb00877093170John Hoford
1286abb7d134c02ac60091108c491dafb00877093170John Hoford        public int size() {
1287abb7d134c02ac60091108c491dafb00877093170John Hoford            return mVGPathMap.size();
1288abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1289abb7d134c02ac60091108c491dafb00877093170John Hoford    }
1290abb7d134c02ac60091108c491dafb00877093170John Hoford
1291abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VPath {
1292abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int LIMIT_ALL = 0;
1293abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int LIMIT_PATH = 1;
1294abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int LIMIT_ROTATE = 2;
1295abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int LIMIT_TRIM_PATH_START = 3;
1296abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int LIMIT_TRIM_PATH_OFFSET = 5;
1297abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int LIMIT_TRIM_PATH_END = 4;
12989453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1299abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int STATE_UNDEFINED=0;
1300abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int STATE_TRUE=1;
1301abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int STATE_FALSE=2;
13029453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1303abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int MAX_STATES = 10;
13049453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
13059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private int[] mThemeAttrs;
13069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1307abb7d134c02ac60091108c491dafb00877093170John Hoford        int mStrokeColor = 0;
1308abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeWidth = 0;
1309abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeOpacity = Float.NaN;
13109453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1311abb7d134c02ac60091108c491dafb00877093170John Hoford        int mFillColor = 0;
1312abb7d134c02ac60091108c491dafb00877093170John Hoford        int mFillRule;
1313abb7d134c02ac60091108c491dafb00877093170John Hoford        float mFillOpacity = Float.NaN;
13149453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1315abb7d134c02ac60091108c491dafb00877093170John Hoford        float mRotate = 0;
1316abb7d134c02ac60091108c491dafb00877093170John Hoford        float mPivotX = 0;
1317abb7d134c02ac60091108c491dafb00877093170John Hoford        float mPivotY = 0;
13189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1319abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathStart = 0;
1320abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathEnd = 1;
1321abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathOffset = 0;
13229453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1323abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean mAnimated = false;
1324abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean mClip = false;
13259453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        Paint.Cap mStrokelineCap = null;
13269453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        Paint.Join mStrokelineJoin = null;
1327abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeMiterlimit = 4;
13289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
13299453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private VNode[] mNode = null;
13309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private String mId;
1331abb7d134c02ac60091108c491dafb00877093170John Hoford        private int[] mCheckState = new int[MAX_STATES];
1332abb7d134c02ac60091108c491dafb00877093170John Hoford        private boolean[] mCheckValue = new boolean[MAX_STATES];
1333abb7d134c02ac60091108c491dafb00877093170John Hoford        private int mNumberOfStates = 0;
1334abb7d134c02ac60091108c491dafb00877093170John Hoford        private int mNumberOfTrue = 0;
1335abb7d134c02ac60091108c491dafb00877093170John Hoford
13369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public VPath() {
13379453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            // Empty constructor.
13389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
13399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
13409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public VPath(VPath p) {
13419453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            copyFrom(p);
13429453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
13439453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1344abb7d134c02ac60091108c491dafb00877093170John Hoford        public void addStateFilter(int state, boolean condition) {
1345abb7d134c02ac60091108c491dafb00877093170John Hoford            int k = 0;
1346abb7d134c02ac60091108c491dafb00877093170John Hoford            while (k < mNumberOfStates) {
1347abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mCheckState[mNumberOfStates] == state)
1348abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1349abb7d134c02ac60091108c491dafb00877093170John Hoford                k++;
1350abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1351abb7d134c02ac60091108c491dafb00877093170John Hoford            mCheckState[k] = state;
1352abb7d134c02ac60091108c491dafb00877093170John Hoford            mCheckValue[k] = condition;
1353abb7d134c02ac60091108c491dafb00877093170John Hoford            if (k==mNumberOfStates){
1354abb7d134c02ac60091108c491dafb00877093170John Hoford                mNumberOfStates++;
1355abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1356abb7d134c02ac60091108c491dafb00877093170John Hoford            if (condition) {
1357abb7d134c02ac60091108c491dafb00877093170John Hoford                mNumberOfTrue++;
1358abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1359abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1360abb7d134c02ac60091108c491dafb00877093170John Hoford
13619453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private int getState(int state){
1362abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mNumberOfStates; i++) {
1363abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mCheckState[mNumberOfStates] == state){
1364abb7d134c02ac60091108c491dafb00877093170John Hoford                    return (mCheckValue[i])?STATE_TRUE:STATE_FALSE;
1365abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1366abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1367abb7d134c02ac60091108c491dafb00877093170John Hoford            return STATE_UNDEFINED;
1368abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1369abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1370abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return the name of the path
1371abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1372abb7d134c02ac60091108c491dafb00877093170John Hoford        public String getName() {
1373abb7d134c02ac60091108c491dafb00877093170John Hoford            return mId;
1374abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1375abb7d134c02ac60091108c491dafb00877093170John Hoford
1376abb7d134c02ac60091108c491dafb00877093170John Hoford        public void toPath(Path path) {
1377abb7d134c02ac60091108c491dafb00877093170John Hoford            path.reset();
1378abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mNode != null) {
1379abb7d134c02ac60091108c491dafb00877093170John Hoford                VNode.createPath(mNode, path);
1380abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1381abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1382abb7d134c02ac60091108c491dafb00877093170John Hoford
1383abb7d134c02ac60091108c491dafb00877093170John Hoford        public String getID(){
1384abb7d134c02ac60091108c491dafb00877093170John Hoford            return mId;
1385abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1386abb7d134c02ac60091108c491dafb00877093170John Hoford
13879453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void inflate(Resources r, AttributeSet attrs, Theme theme) {
13889453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawablePath);
13899453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int[] themeAttrs = a.extractThemeAttrs();
13909453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            mThemeAttrs = themeAttrs;
13919453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1392abb7d134c02ac60091108c491dafb00877093170John Hoford            mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, false);
1393abb7d134c02ac60091108c491dafb00877093170John Hoford            mId = a.getString(R.styleable.VectorDrawablePath_name);
1394abb7d134c02ac60091108c491dafb00877093170John Hoford            mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData));
1395abb7d134c02ac60091108c491dafb00877093170John Hoford
13969453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fill] == 0) {
13979453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, 0);
13989453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
13999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14009453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null
14019453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_fillOpacity] == 0) {
14029453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, Float.NaN);
1403abb7d134c02ac60091108c491dafb00877093170John Hoford            }
14049453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1405abb7d134c02ac60091108c491dafb00877093170John Hoford            mRotate = a.getFloat(R.styleable.VectorDrawablePath_rotation, 0);
1406abb7d134c02ac60091108c491dafb00877093170John Hoford            mPivotX = a.getFloat(R.styleable.VectorDrawablePath_pivotX, 0);
1407abb7d134c02ac60091108c491dafb00877093170John Hoford            mPivotY = a.getFloat(R.styleable.VectorDrawablePath_pivotY, 0);
14089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14099453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int lineCap  = a.getInt(R.styleable.VectorDrawablePath_strokeLineCap, 0);
1410abb7d134c02ac60091108c491dafb00877093170John Hoford            switch (lineCap) {
1411abb7d134c02ac60091108c491dafb00877093170John Hoford                case LINECAP_BUTT:
1412abb7d134c02ac60091108c491dafb00877093170John Hoford                    mStrokelineCap = Paint.Cap.BUTT;
1413abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1414abb7d134c02ac60091108c491dafb00877093170John Hoford                case LINECAP_ROUND:
1415abb7d134c02ac60091108c491dafb00877093170John Hoford                    mStrokelineCap = Paint.Cap.ROUND;
1416abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1417abb7d134c02ac60091108c491dafb00877093170John Hoford                case LINECAP_SQUARE:
1418abb7d134c02ac60091108c491dafb00877093170John Hoford                    mStrokelineCap = Paint.Cap.SQUARE;
1419abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1420abb7d134c02ac60091108c491dafb00877093170John Hoford            }
14219453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14229453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int lineJoin =  a.getInt(R.styleable.VectorDrawablePath_strokeLineJoin, 0);
1423abb7d134c02ac60091108c491dafb00877093170John Hoford            switch (lineJoin) {
1424abb7d134c02ac60091108c491dafb00877093170John Hoford                case LINEJOIN_MITER:
1425abb7d134c02ac60091108c491dafb00877093170John Hoford                    mStrokelineJoin = Paint.Join.MITER;
1426abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1427abb7d134c02ac60091108c491dafb00877093170John Hoford                case LINEJOIN_ROUND:
1428abb7d134c02ac60091108c491dafb00877093170John Hoford                    mStrokelineJoin = Paint.Join.ROUND;
1429abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1430abb7d134c02ac60091108c491dafb00877093170John Hoford                case LINEJOIN_BEVEL:
1431abb7d134c02ac60091108c491dafb00877093170John Hoford                    mStrokelineJoin = Paint.Join.BEVEL;
1432abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1433abb7d134c02ac60091108c491dafb00877093170John Hoford            }
14349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1435abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokeMiterlimit = a.getFloat(R.styleable.VectorDrawablePath_strokeMiterLimit,
1436abb7d134c02ac60091108c491dafb00877093170John Hoford                    mStrokeMiterlimit);
14379453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_stroke] == 0) {
14399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor);
1440abb7d134c02ac60091108c491dafb00877093170John Hoford            }
14419453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14429453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null
14439453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeOpacity] == 0) {
14449453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeOpacity = a.getFloat(
14459453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                        R.styleable.VectorDrawablePath_strokeOpacity, Float.NaN);
14469453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
14479453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1448abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, 0);
1449abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, 1);
1450abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrimPathOffset = a.getFloat(R.styleable.VectorDrawablePath_trimPathOffset, 0);
1451abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrimPathStart = a.getFloat(R.styleable.VectorDrawablePath_trimPathStart, 0);
14529453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14539453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int[] states = {
14549453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    R.styleable.VectorDrawablePath_state_activated,
1455abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_checkable,
1456abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_checked,
1457abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_enabled,
1458abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_focused,
1459abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_hovered,
1460abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_pressed,
1461abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_selected,
14629453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    R.styleable.VectorDrawablePath_state_window_focused
14639453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            };
14649453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14659453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int N = states.length;
14669453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            for (int i = 0; i < N; i++) {
14679453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final int state = states[i];
1468abb7d134c02ac60091108c491dafb00877093170John Hoford                if (a.hasValue(state)) {
1469abb7d134c02ac60091108c491dafb00877093170John Hoford                    addStateFilter(state, a.getBoolean(state, false));
1470abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1471abb7d134c02ac60091108c491dafb00877093170John Hoford            }
14729453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14739453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            updateColorAlphas();
14749453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1475abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
1476abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1477abb7d134c02ac60091108c491dafb00877093170John Hoford
14789453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean canApplyTheme() {
14799453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return mThemeAttrs != null;
14809453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
14819453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14829453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void applyTheme(Theme t) {
14839453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (mThemeAttrs == null) {
14849453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                return;
14859453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
14869453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14879453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final TypedArray a = t.resolveAttributes(
14889453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    mThemeAttrs, R.styleable.VectorDrawablePath, 0, 0);
14899453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14909453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (a.hasValue(R.styleable.VectorDrawablePath_fill)) {
14919453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, 0);
14929453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
14939453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (a.hasValue(R.styleable.VectorDrawablePath_fillOpacity)) {
14959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, Float.NaN);
14969453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
14979453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14989453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (a.hasValue(R.styleable.VectorDrawablePath_stroke)) {
14999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor);
15009453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
15019453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15029453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (a.hasValue(R.styleable.VectorDrawablePath_strokeOpacity)) {
15039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeOpacity = a.getFloat(
15049453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                        R.styleable.VectorDrawablePath_strokeOpacity, Float.NaN);
15059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
15069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            updateColorAlphas();
15089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
15099453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15109453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private void updateColorAlphas() {
15119453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (!Float.isNaN(mFillOpacity)) {
15129453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mFillColor &= 0x00FFFFFF;
15139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mFillColor |= ((int) (0xFF * mFillOpacity)) << 24;
15149453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
15159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (!Float.isNaN(mStrokeOpacity)) {
15179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor &= 0x00FFFFFF;
15189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor |= ((int) (0xFF * mStrokeOpacity)) << 24;
15199453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
15209453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
15219453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1522abb7d134c02ac60091108c491dafb00877093170John Hoford        private static int nextStart(String s, int end) {
1523abb7d134c02ac60091108c491dafb00877093170John Hoford            char c;
1524abb7d134c02ac60091108c491dafb00877093170John Hoford
1525abb7d134c02ac60091108c491dafb00877093170John Hoford            while (end < s.length()) {
1526abb7d134c02ac60091108c491dafb00877093170John Hoford                c = s.charAt(end);
1527abb7d134c02ac60091108c491dafb00877093170John Hoford                if (((c - 'A') * (c - 'Z') <= 0) || (((c - 'a') * (c - 'z') <= 0))) {
1528abb7d134c02ac60091108c491dafb00877093170John Hoford                    return end;
1529abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1530abb7d134c02ac60091108c491dafb00877093170John Hoford                end++;
1531abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1532abb7d134c02ac60091108c491dafb00877093170John Hoford            return end;
1533abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1534abb7d134c02ac60091108c491dafb00877093170John Hoford
1535abb7d134c02ac60091108c491dafb00877093170John Hoford        private void addNode(ArrayList<VectorDrawable.VNode> list, char cmd, float[] val) {
1536abb7d134c02ac60091108c491dafb00877093170John Hoford            list.add(new VectorDrawable.VNode(cmd, val));
1537abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1538abb7d134c02ac60091108c491dafb00877093170John Hoford
1539abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1540abb7d134c02ac60091108c491dafb00877093170John Hoford         * parse the floats in the string
1541abb7d134c02ac60091108c491dafb00877093170John Hoford         * this is an optimized version of
1542abb7d134c02ac60091108c491dafb00877093170John Hoford         * parseFloat(s.split(",|\\s"));
1543abb7d134c02ac60091108c491dafb00877093170John Hoford         *
1544abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param s the string containing a command and list of floats
1545abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return array of floats
1546abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1547abb7d134c02ac60091108c491dafb00877093170John Hoford        private static float[] getFloats(String s) {
1548abb7d134c02ac60091108c491dafb00877093170John Hoford            if (s.charAt(0) == 'z' | s.charAt(0) == 'Z') {
1549abb7d134c02ac60091108c491dafb00877093170John Hoford                return new float[0];
1550abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1551abb7d134c02ac60091108c491dafb00877093170John Hoford            try {
1552abb7d134c02ac60091108c491dafb00877093170John Hoford                float[] tmp = new float[s.length()];
1553abb7d134c02ac60091108c491dafb00877093170John Hoford                int count = 0;
1554abb7d134c02ac60091108c491dafb00877093170John Hoford                int pos = 1, end;
1555abb7d134c02ac60091108c491dafb00877093170John Hoford                while ((end = extract(s, pos)) >= 0) {
1556abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (pos < end) {
1557abb7d134c02ac60091108c491dafb00877093170John Hoford                        tmp[count++] = Float.parseFloat(s.substring(pos, end));
1558abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1559abb7d134c02ac60091108c491dafb00877093170John Hoford                    pos = end + 1;
1560abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1561abb7d134c02ac60091108c491dafb00877093170John Hoford                // handle the final float if there is one
1562abb7d134c02ac60091108c491dafb00877093170John Hoford                if (pos < s.length()) {
1563abb7d134c02ac60091108c491dafb00877093170John Hoford                    tmp[count++] = Float.parseFloat(s.substring(pos, s.length()));
1564abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1565abb7d134c02ac60091108c491dafb00877093170John Hoford                return Arrays.copyOf(tmp, count);
1566abb7d134c02ac60091108c491dafb00877093170John Hoford            } catch (NumberFormatException e){
1567abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.e(LOGTAG,"error in parsing \""+s+"\"");
1568abb7d134c02ac60091108c491dafb00877093170John Hoford                throw e;
1569abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1570abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1571abb7d134c02ac60091108c491dafb00877093170John Hoford
1572abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1573abb7d134c02ac60091108c491dafb00877093170John Hoford         * calculate the position of the next comma or space
1574abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param s the string to search
1575abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param start the position to start searching
1576abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return the position of the next comma or space or -1 if none found
1577abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1578abb7d134c02ac60091108c491dafb00877093170John Hoford        private static int extract(String s, int start) {
1579abb7d134c02ac60091108c491dafb00877093170John Hoford            int space = s.indexOf(' ', start);
1580abb7d134c02ac60091108c491dafb00877093170John Hoford            int comma = s.indexOf(',', start);
1581abb7d134c02ac60091108c491dafb00877093170John Hoford            if (space == -1) {
1582abb7d134c02ac60091108c491dafb00877093170John Hoford                return comma;
1583abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1584abb7d134c02ac60091108c491dafb00877093170John Hoford            if (comma == -1) {
1585abb7d134c02ac60091108c491dafb00877093170John Hoford                return space;
1586abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1587abb7d134c02ac60091108c491dafb00877093170John Hoford            return (comma > space) ? space : comma;
1588abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1589abb7d134c02ac60091108c491dafb00877093170John Hoford
1590abb7d134c02ac60091108c491dafb00877093170John Hoford        private VectorDrawable.VNode[] parsePath(String value) {
1591abb7d134c02ac60091108c491dafb00877093170John Hoford            int start = 0;
1592abb7d134c02ac60091108c491dafb00877093170John Hoford            int end = 1;
1593abb7d134c02ac60091108c491dafb00877093170John Hoford
1594abb7d134c02ac60091108c491dafb00877093170John Hoford            ArrayList<VectorDrawable.VNode> list = new ArrayList<VectorDrawable.VNode>();
1595abb7d134c02ac60091108c491dafb00877093170John Hoford            while (end < value.length()) {
1596abb7d134c02ac60091108c491dafb00877093170John Hoford                end = nextStart(value, end);
1597abb7d134c02ac60091108c491dafb00877093170John Hoford                String s = value.substring(start, end);
1598abb7d134c02ac60091108c491dafb00877093170John Hoford                float[] val = getFloats(s);
1599abb7d134c02ac60091108c491dafb00877093170John Hoford                addNode(list, s.charAt(0), val);
1600abb7d134c02ac60091108c491dafb00877093170John Hoford
1601abb7d134c02ac60091108c491dafb00877093170John Hoford                start = end;
1602abb7d134c02ac60091108c491dafb00877093170John Hoford                end++;
1603abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1604abb7d134c02ac60091108c491dafb00877093170John Hoford            if ((end - start) == 1 && start < value.length()) {
1605abb7d134c02ac60091108c491dafb00877093170John Hoford
1606abb7d134c02ac60091108c491dafb00877093170John Hoford                addNode(list, value.charAt(start), new float[0]);
1607abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1608abb7d134c02ac60091108c491dafb00877093170John Hoford            return list.toArray(new VectorDrawable.VNode[list.size()]);
1609abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1610abb7d134c02ac60091108c491dafb00877093170John Hoford
1611abb7d134c02ac60091108c491dafb00877093170John Hoford        public void copyFrom(VPath p1) {
1612abb7d134c02ac60091108c491dafb00877093170John Hoford            mNode = new VNode[p1.mNode.length];
1613abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mNode.length; i++) {
1614abb7d134c02ac60091108c491dafb00877093170John Hoford                mNode[i] = new VNode(p1.mNode[i]);
1615abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1616abb7d134c02ac60091108c491dafb00877093170John Hoford            mId = p1.mId;
1617abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokeColor = p1.mStrokeColor;
1618abb7d134c02ac60091108c491dafb00877093170John Hoford            mFillColor = p1.mFillColor;
1619abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokeWidth = p1.mStrokeWidth;
1620abb7d134c02ac60091108c491dafb00877093170John Hoford            mRotate = p1.mRotate;
1621abb7d134c02ac60091108c491dafb00877093170John Hoford            mPivotX = p1.mPivotX;
1622abb7d134c02ac60091108c491dafb00877093170John Hoford            mPivotY = p1.mPivotY;
1623abb7d134c02ac60091108c491dafb00877093170John Hoford            mAnimated = p1.mAnimated;
1624abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrimPathStart = p1.mTrimPathStart;
1625abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrimPathEnd = p1.mTrimPathEnd;
1626abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrimPathOffset = p1.mTrimPathOffset;
1627abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokelineCap = p1.mStrokelineCap;
1628abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokelineJoin = p1.mStrokelineJoin;
1629abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokeMiterlimit = p1.mStrokeMiterlimit;
1630abb7d134c02ac60091108c491dafb00877093170John Hoford            mNumberOfStates = p1.mNumberOfStates;
1631abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mNumberOfStates; i++) {
1632abb7d134c02ac60091108c491dafb00877093170John Hoford                mCheckState[i] = p1.mCheckState[i];
1633abb7d134c02ac60091108c491dafb00877093170John Hoford                mCheckValue[i] = p1.mCheckValue[i];
1634abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1635abb7d134c02ac60091108c491dafb00877093170John Hoford
1636abb7d134c02ac60091108c491dafb00877093170John Hoford            mFillRule = p1.mFillRule;
1637abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1638abb7d134c02ac60091108c491dafb00877093170John Hoford
1639abb7d134c02ac60091108c491dafb00877093170John Hoford        public static VPath interpolate(float t, VPath p1, VPath p2, VPath returnPath, int limit) {
1640abb7d134c02ac60091108c491dafb00877093170John Hoford            if (limit == LIMIT_ALL || limit == LIMIT_PATH) {
1641abb7d134c02ac60091108c491dafb00877093170John Hoford                if (returnPath.mNode == null || returnPath.mNode.length != p1.mNode.length) {
1642abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mNode = new VNode[p1.mNode.length];
1643abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1644abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int i = 0; i < returnPath.mNode.length; i++) {
1645abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (returnPath.mNode[i] == null) {
1646abb7d134c02ac60091108c491dafb00877093170John Hoford                        returnPath.mNode[i] = new VNode(p1.mNode[i], p2.mNode[i], t);
1647abb7d134c02ac60091108c491dafb00877093170John Hoford                    } else {
1648abb7d134c02ac60091108c491dafb00877093170John Hoford                        returnPath.mNode[i].interpolate(p1.mNode[i], p2.mNode[i], t);
1649abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1650abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1651abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1652abb7d134c02ac60091108c491dafb00877093170John Hoford            float t1 = 1 - t;
1653abb7d134c02ac60091108c491dafb00877093170John Hoford            switch (limit) {
1654abb7d134c02ac60091108c491dafb00877093170John Hoford                case LIMIT_ALL:
1655abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mRotate = t1 * p1.mRotate + t * p2.mRotate;
1656abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mPivotX = t1 * p1.mPivotX + t * p2.mPivotX;
1657abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mPivotY = t1 * p1.mPivotY + t * p2.mPivotY;
1658abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mClip = p1.mClip | p2.mClip;
1659abb7d134c02ac60091108c491dafb00877093170John Hoford
1660abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mTrimPathStart = t1 * p1.mTrimPathStart + t * p2.mTrimPathStart;
1661abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mTrimPathEnd = t1 * p1.mTrimPathEnd + t * p2.mTrimPathEnd;
1662abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mTrimPathOffset = t1 * p1.mTrimPathOffset + t * p2.mTrimPathOffset;
1663abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mStrokeMiterlimit =
1664abb7d134c02ac60091108c491dafb00877093170John Hoford                            t1 * p1.mStrokeMiterlimit + t * p2.mStrokeMiterlimit;
1665abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mStrokelineCap = p1.mStrokelineCap;
1666abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (returnPath.mStrokelineCap == null) {
1667abb7d134c02ac60091108c491dafb00877093170John Hoford                        returnPath.mStrokelineCap = p2.mStrokelineCap;
1668abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1669abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mStrokelineJoin = p1.mStrokelineJoin;
1670abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (returnPath.mStrokelineJoin == null) {
1671abb7d134c02ac60091108c491dafb00877093170John Hoford                        returnPath.mStrokelineJoin = p2.mStrokelineJoin;
1672abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1673abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mFillRule = p1.mFillRule;
1674abb7d134c02ac60091108c491dafb00877093170John Hoford
1675abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mStrokeColor = rgbInterpolate(t, p1.mStrokeColor, p2.mStrokeColor);
1676abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mFillColor = rgbInterpolate(t, p1.mFillColor, p2.mFillColor);
1677abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mStrokeWidth = t1 * p1.mStrokeWidth + t * p2.mStrokeWidth;
1678abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mNumberOfStates = p1.mNumberOfStates;
1679abb7d134c02ac60091108c491dafb00877093170John Hoford                    for (int i = 0; i < returnPath.mNumberOfStates; i++) {
1680abb7d134c02ac60091108c491dafb00877093170John Hoford                        returnPath.mCheckState[i] = p1.mCheckState[i];
1681abb7d134c02ac60091108c491dafb00877093170John Hoford                        returnPath.mCheckValue[i] = p1.mCheckValue[i];
1682abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1683abb7d134c02ac60091108c491dafb00877093170John Hoford                    for (int i = 0; i < p2.mNumberOfStates; i++) {
1684abb7d134c02ac60091108c491dafb00877093170John Hoford                        returnPath.addStateFilter(p2.mCheckState[i], p2.mCheckValue[i]);
1685abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1686abb7d134c02ac60091108c491dafb00877093170John Hoford
1687abb7d134c02ac60091108c491dafb00877093170John Hoford                    int count = 0;
1688abb7d134c02ac60091108c491dafb00877093170John Hoford                    for (int i = 0; i < returnPath.mNumberOfStates; i++) {
1689abb7d134c02ac60091108c491dafb00877093170John Hoford                        if (returnPath.mCheckValue[i]) {
1690abb7d134c02ac60091108c491dafb00877093170John Hoford                            count++;
1691abb7d134c02ac60091108c491dafb00877093170John Hoford                        }
1692abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1693abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mNumberOfTrue = count;
1694abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1695abb7d134c02ac60091108c491dafb00877093170John Hoford                case LIMIT_ROTATE:
1696abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mRotate = t1 * p1.mRotate + t * p2.mRotate;
1697abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1698abb7d134c02ac60091108c491dafb00877093170John Hoford                case LIMIT_TRIM_PATH_END:
1699abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mTrimPathEnd = t1 * p1.mTrimPathEnd + t * p2.mTrimPathEnd;
1700abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1701abb7d134c02ac60091108c491dafb00877093170John Hoford                case LIMIT_TRIM_PATH_OFFSET:
1702abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mTrimPathOffset = t1 * p1.mTrimPathOffset + t * p2.mTrimPathOffset;
1703abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1704abb7d134c02ac60091108c491dafb00877093170John Hoford                case LIMIT_TRIM_PATH_START:
1705abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mTrimPathStart = t1 * p1.mTrimPathStart + t * p2.mTrimPathStart;
1706abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1707abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1708abb7d134c02ac60091108c491dafb00877093170John Hoford            return returnPath;
1709abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1710abb7d134c02ac60091108c491dafb00877093170John Hoford
1711abb7d134c02ac60091108c491dafb00877093170John Hoford        private static int rgbInterpolate(float t, int color1, int color2) {
1712abb7d134c02ac60091108c491dafb00877093170John Hoford            int ret;
1713abb7d134c02ac60091108c491dafb00877093170John Hoford            if (color1 == color2) {
1714abb7d134c02ac60091108c491dafb00877093170John Hoford                return color2;
1715abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1716abb7d134c02ac60091108c491dafb00877093170John Hoford            if (color1 == 0) {
1717abb7d134c02ac60091108c491dafb00877093170John Hoford                return color2;
1718abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1719abb7d134c02ac60091108c491dafb00877093170John Hoford            if (color2 == 0) {
1720abb7d134c02ac60091108c491dafb00877093170John Hoford                return color1;
1721abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1722abb7d134c02ac60091108c491dafb00877093170John Hoford
1723abb7d134c02ac60091108c491dafb00877093170John Hoford            float t1 = 1 - t;
1724abb7d134c02ac60091108c491dafb00877093170John Hoford            ret = 0xFF & (((int) ((color1 & 0xFF) * t1 + (color2 & 0xFF) * t)));
1725abb7d134c02ac60091108c491dafb00877093170John Hoford            color1 >>= 8;
1726abb7d134c02ac60091108c491dafb00877093170John Hoford                    color2 >>= 8;
1727abb7d134c02ac60091108c491dafb00877093170John Hoford
1728abb7d134c02ac60091108c491dafb00877093170John Hoford                    ret |= 0xFF00 & (((int) ((color1 & 0xFF) * t1 + (color2 & 0xFF) * t)) << 8);
1729abb7d134c02ac60091108c491dafb00877093170John Hoford                    color1 >>= 8;
1730abb7d134c02ac60091108c491dafb00877093170John Hoford                    color2 >>= 8;
1731abb7d134c02ac60091108c491dafb00877093170John Hoford            ret |= 0xFF0000 & (((int) ((color1 & 0xFF) * t1 + (color2 & 0xFF) * t)) << 16);
1732abb7d134c02ac60091108c491dafb00877093170John Hoford            color1 >>= 8;
1733abb7d134c02ac60091108c491dafb00877093170John Hoford            color2 >>= 8;
1734abb7d134c02ac60091108c491dafb00877093170John Hoford            ret |= 0xFF000000 & (((int) ((color1 & 0xFF) * t1 + (color2 & 0xFF) * t)) << 24);
1735abb7d134c02ac60091108c491dafb00877093170John Hoford
1736abb7d134c02ac60091108c491dafb00877093170John Hoford            return ret;
1737abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1738abb7d134c02ac60091108c491dafb00877093170John Hoford
1739abb7d134c02ac60091108c491dafb00877093170John Hoford        public boolean isVisible(int[] state) {
1740abb7d134c02ac60091108c491dafb00877093170John Hoford            int match = 0;
1741abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < state.length; i++) {
1742abb7d134c02ac60091108c491dafb00877093170John Hoford                int v = getState(state[i]);
1743abb7d134c02ac60091108c491dafb00877093170John Hoford                if (v != STATE_UNDEFINED) {
1744abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (v==STATE_TRUE) {
1745abb7d134c02ac60091108c491dafb00877093170John Hoford                        match++;
1746abb7d134c02ac60091108c491dafb00877093170John Hoford                    } else {
1747abb7d134c02ac60091108c491dafb00877093170John Hoford                        return false;
1748abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1749abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1750abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1751abb7d134c02ac60091108c491dafb00877093170John Hoford            return match == mNumberOfTrue;
1752abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1753abb7d134c02ac60091108c491dafb00877093170John Hoford    }
1754abb7d134c02ac60091108c491dafb00877093170John Hoford
1755abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VNode {
17569453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private static float[] current = new float[4];
17579453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1758abb7d134c02ac60091108c491dafb00877093170John Hoford        char type;
1759abb7d134c02ac60091108c491dafb00877093170John Hoford        float[] params;
17609453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1761abb7d134c02ac60091108c491dafb00877093170John Hoford        public VNode(char type, float[] params) {
1762abb7d134c02ac60091108c491dafb00877093170John Hoford            this.type = type;
1763abb7d134c02ac60091108c491dafb00877093170John Hoford            this.params = params;
1764abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1765abb7d134c02ac60091108c491dafb00877093170John Hoford
1766abb7d134c02ac60091108c491dafb00877093170John Hoford        public VNode(VNode n) {
1767abb7d134c02ac60091108c491dafb00877093170John Hoford            this.type = n.type;
1768abb7d134c02ac60091108c491dafb00877093170John Hoford            this.params = Arrays.copyOf(n.params, n.params.length);
1769abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1770abb7d134c02ac60091108c491dafb00877093170John Hoford
1771abb7d134c02ac60091108c491dafb00877093170John Hoford        public VNode(VNode n1, VNode n2, float t) {
1772abb7d134c02ac60091108c491dafb00877093170John Hoford            this.type = n1.type;
1773abb7d134c02ac60091108c491dafb00877093170John Hoford            this.params = new float[n1.params.length];
1774abb7d134c02ac60091108c491dafb00877093170John Hoford            interpolate(n1, n2, t);
1775abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1776abb7d134c02ac60091108c491dafb00877093170John Hoford
1777abb7d134c02ac60091108c491dafb00877093170John Hoford        private boolean match(VNode n) {
1778abb7d134c02ac60091108c491dafb00877093170John Hoford            if (n.type != type) {
1779abb7d134c02ac60091108c491dafb00877093170John Hoford                return false;
1780abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1781abb7d134c02ac60091108c491dafb00877093170John Hoford            return (params.length == n.params.length);
1782abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1783abb7d134c02ac60091108c491dafb00877093170John Hoford
1784abb7d134c02ac60091108c491dafb00877093170John Hoford        public void interpolate(VNode n1, VNode n2, float t) {
1785abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < n1.params.length; i++) {
1786abb7d134c02ac60091108c491dafb00877093170John Hoford                params[i] = n1.params[i] * (1 - t) + n2.params[i] * t;
1787abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1788abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1789abb7d134c02ac60091108c491dafb00877093170John Hoford
1790abb7d134c02ac60091108c491dafb00877093170John Hoford        private void nodeListToPath(VNode[] node, Path path) {
1791abb7d134c02ac60091108c491dafb00877093170John Hoford            float[] current = new float[4];
1792abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < node.length; i++) {
1793abb7d134c02ac60091108c491dafb00877093170John Hoford                addCommand(path, current, node[i].type, node[i].params);
1794abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1795abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1796abb7d134c02ac60091108c491dafb00877093170John Hoford
1797abb7d134c02ac60091108c491dafb00877093170John Hoford        public static void createPath(VNode[] node, Path path) {
1798abb7d134c02ac60091108c491dafb00877093170John Hoford            Arrays.fill(current,0);
1799abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < node.length; i++) {
1800abb7d134c02ac60091108c491dafb00877093170John Hoford                addCommand(path, current, node[i].type, node[i].params);
1801abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1802abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1803abb7d134c02ac60091108c491dafb00877093170John Hoford
1804abb7d134c02ac60091108c491dafb00877093170John Hoford        private static void addCommand(Path path, float[] current, char cmd, float[] val) {
1805abb7d134c02ac60091108c491dafb00877093170John Hoford
1806abb7d134c02ac60091108c491dafb00877093170John Hoford            int incr = 2;
1807abb7d134c02ac60091108c491dafb00877093170John Hoford            float currentX = current[0];
1808abb7d134c02ac60091108c491dafb00877093170John Hoford            float currentY = current[1];
1809abb7d134c02ac60091108c491dafb00877093170John Hoford            float ctrlPointX = current[2];
1810abb7d134c02ac60091108c491dafb00877093170John Hoford            float ctrlPointY = current[3];
1811abb7d134c02ac60091108c491dafb00877093170John Hoford
1812abb7d134c02ac60091108c491dafb00877093170John Hoford            switch (cmd) {
1813abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'z':
1814abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'Z':
1815abb7d134c02ac60091108c491dafb00877093170John Hoford                    path.close();
1816abb7d134c02ac60091108c491dafb00877093170John Hoford                    return;
1817abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'm':
1818abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'M':
1819abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'l':
1820abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'L':
1821abb7d134c02ac60091108c491dafb00877093170John Hoford                case 't':
1822abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'T':
1823abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 2;
1824abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1825abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'h':
1826abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'H':
1827abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'v':
1828abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'V':
1829abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 1;
1830abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1831abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'c':
1832abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'C':
1833abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 6;
1834abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1835abb7d134c02ac60091108c491dafb00877093170John Hoford                case 's':
1836abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'S':
1837abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'q':
1838abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'Q':
1839abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 4;
1840abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1841abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'a':
1842abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'A':
1843abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 7;
1844abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1845abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1846abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int k = 0; k < val.length; k += incr) {
1847abb7d134c02ac60091108c491dafb00877093170John Hoford                // TODO: build test to prove all permutations work
1848abb7d134c02ac60091108c491dafb00877093170John Hoford                switch (cmd) {
1849abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'm': // moveto - Start a new sub-path (relative)
1850abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rMoveTo(val[k + 0], val[k + 1]);
1851abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1852abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1853abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1854abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'M': // moveto - Start a new sub-path
1855abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.moveTo(val[k + 0], val[k + 1]);
1856abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1857abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 1];
1858abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1859abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'l': // lineto - Draw a line from the current point (relative)
1860abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(val[k + 0], val[k + 1]);
1861abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1862abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1863abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1864abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'L': // lineto - Draw a line from the current point
1865abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(val[k + 0], val[k + 1]);
1866abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1867abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 1];
1868abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1869abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'z': // closepath - Close the current subpath
1870abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'Z': // closepath - Close the current subpath
1871abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.close();
1872abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1873abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'h': // horizontal lineto - Draws a horizontal line (relative)
1874abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(val[k + 0], 0);
1875abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1876abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1877abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'H': // horizontal lineto - Draws a horizontal line
1878abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(val[k + 0], currentY);
1879abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1880abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1881abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'v': // vertical lineto - Draws a vertical line from the current point (r)
1882abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(0, val[k + 0]);
1883abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 0];
1884abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1885abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'V': // vertical lineto - Draws a vertical line from the current point
1886abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(currentX, val[k + 0]);
1887abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 0];
1888abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1889abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'c': // curveto - Draws a cubic Bézier curve (relative)
1890abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rCubicTo(val[k + 0],
1891abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
1892abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
1893abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3],
1894abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 4],
1895abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 5]);
1896abb7d134c02ac60091108c491dafb00877093170John Hoford
1897abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX + val[k + 2];
1898abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY + val[k + 3];
1899abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 4];
1900abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 5];
1901abb7d134c02ac60091108c491dafb00877093170John Hoford
1902abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1903abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'C': // curveto - Draws a cubic Bézier curve
1904abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.cubicTo(val[k + 0],
1905abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
1906abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
1907abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3],
1908abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 4],
1909abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 5]);
1910abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 4];
1911abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 5];
1912abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 2];
1913abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 3];
1914abb7d134c02ac60091108c491dafb00877093170John Hoford
1915abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1916abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp)
1917abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rCubicTo(currentX - ctrlPointX, currentY  - ctrlPointY,
1918abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1],
1919abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2], val[k + 3]);
1920abb7d134c02ac60091108c491dafb00877093170John Hoford
1921abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX + val[k + 0];
1922abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY + val[k + 1];
1923abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 2];
1924abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 3];
1925abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1926abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp)
1927abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.cubicTo(2 * currentX - ctrlPointX,
1928abb7d134c02ac60091108c491dafb00877093170John Hoford                                2 * currentY - ctrlPointY,
1929abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0],
1930abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
1931abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
1932abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3]);
1933abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 2];
1934abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 3];
1935abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 0];
1936abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 1];
1937abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1938abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'q': // Draws a quadratic Bézier (relative)
1939abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
1940abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 2];
1941abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 3];
1942abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 0];
1943abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 1];
1944abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1945abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'Q': // Draws a quadratic Bézier
1946abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
1947abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 2];
1948abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 3];
1949abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 0];
1950abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 1];
1951abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1952abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 't': // Draws a quadratic Bézier curve(reflective control point)(relative)
1953abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rQuadTo(currentX - ctrlPointX, currentY - ctrlPointY,
1954abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1]);
1955abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = ctrlPointX + currentX;
1956abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = ctrlPointY + currentY;
1957abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1958abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1959abb7d134c02ac60091108c491dafb00877093170John Hoford
1960abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1961abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'T': // Draws a quadratic Bézier curve (reflective control point)
1962abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.quadTo(currentX * 2 - ctrlPointX, currentY * 2 - ctrlPointY,
1963abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1]);
1964abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1965abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 1]; // TODO: Check this logic
1966abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = -(val[k + 0] - currentX);
1967abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = -(val[k + 1] - currentY);
1968abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1969abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'a': // Draws an elliptical arc
1970abb7d134c02ac60091108c491dafb00877093170John Hoford                        // (rx ry x-axis-rotation large-arc-flag sweep-flag x y)
1971abb7d134c02ac60091108c491dafb00877093170John Hoford                        drawArc(path,
1972abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentX,
1973abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentY,
1974abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 5] + currentX,
1975abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 6] + currentY,
1976abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0],
1977abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
1978abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
1979abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3] != 0,
1980abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 4] != 0);
1981abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 5];
1982abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 6];
1983abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX;
1984abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY;
1985abb7d134c02ac60091108c491dafb00877093170John Hoford
1986abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1987abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'A': // Draws an elliptical arc
1988abb7d134c02ac60091108c491dafb00877093170John Hoford                        drawArc(path,
1989abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentX,
1990abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentY,
1991abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 5],
1992abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 6],
1993abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0],
1994abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
1995abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
1996abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3] != 0,
1997abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 4] != 0);
1998abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 5];
1999abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 6];
2000abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX;
2001abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY;
2002abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
2003abb7d134c02ac60091108c491dafb00877093170John Hoford                }
2004abb7d134c02ac60091108c491dafb00877093170John Hoford            }
2005abb7d134c02ac60091108c491dafb00877093170John Hoford            current[0] = currentX;
2006abb7d134c02ac60091108c491dafb00877093170John Hoford            current[1] = currentY;
2007abb7d134c02ac60091108c491dafb00877093170John Hoford            current[2] = ctrlPointX;
2008abb7d134c02ac60091108c491dafb00877093170John Hoford            current[3] = ctrlPointY;
2009abb7d134c02ac60091108c491dafb00877093170John Hoford        }
2010abb7d134c02ac60091108c491dafb00877093170John Hoford
2011abb7d134c02ac60091108c491dafb00877093170John Hoford        private static void drawArc(Path p,
2012abb7d134c02ac60091108c491dafb00877093170John Hoford                float x0,
2013abb7d134c02ac60091108c491dafb00877093170John Hoford                float y0,
2014abb7d134c02ac60091108c491dafb00877093170John Hoford                float x1,
2015abb7d134c02ac60091108c491dafb00877093170John Hoford                float y1,
2016abb7d134c02ac60091108c491dafb00877093170John Hoford                float a,
2017abb7d134c02ac60091108c491dafb00877093170John Hoford                float b,
2018abb7d134c02ac60091108c491dafb00877093170John Hoford                float theta,
2019abb7d134c02ac60091108c491dafb00877093170John Hoford                boolean isMoreThanHalf,
2020abb7d134c02ac60091108c491dafb00877093170John Hoford                boolean isPositiveArc) {
2021abb7d134c02ac60091108c491dafb00877093170John Hoford
2022abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Convert rotation angle from degrees to radians */
2023abb7d134c02ac60091108c491dafb00877093170John Hoford            double thetaD = Math.toRadians(theta);
2024abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Pre-compute rotation matrix entries */
2025abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosTheta = Math.cos(thetaD);
2026abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinTheta = Math.sin(thetaD);
2027abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Transform (x0, y0) and (x1, y1) into unit space */
2028abb7d134c02ac60091108c491dafb00877093170John Hoford            /* using (inverse) rotation, followed by (inverse) scale */
2029abb7d134c02ac60091108c491dafb00877093170John Hoford            double x0p = (x0 * cosTheta + y0 * sinTheta) / a;
2030abb7d134c02ac60091108c491dafb00877093170John Hoford            double y0p = (-x0 * sinTheta + y0 * cosTheta) / b;
2031abb7d134c02ac60091108c491dafb00877093170John Hoford            double x1p = (x1 * cosTheta + y1 * sinTheta) / a;
2032abb7d134c02ac60091108c491dafb00877093170John Hoford            double y1p = (-x1 * sinTheta + y1 * cosTheta) / b;
2033abb7d134c02ac60091108c491dafb00877093170John Hoford
2034abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Compute differences and averages */
2035abb7d134c02ac60091108c491dafb00877093170John Hoford            double dx = x0p - x1p;
2036abb7d134c02ac60091108c491dafb00877093170John Hoford            double dy = y0p - y1p;
2037abb7d134c02ac60091108c491dafb00877093170John Hoford            double xm = (x0p + x1p) / 2;
2038abb7d134c02ac60091108c491dafb00877093170John Hoford            double ym = (y0p + y1p) / 2;
2039abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Solve for intersecting unit circles */
2040abb7d134c02ac60091108c491dafb00877093170John Hoford            double dsq = dx * dx + dy * dy;
2041abb7d134c02ac60091108c491dafb00877093170John Hoford            if (dsq == 0.0) {
2042abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.w(LOGTAG, " Points are coincident");
2043abb7d134c02ac60091108c491dafb00877093170John Hoford                return; /* Points are coincident */
2044abb7d134c02ac60091108c491dafb00877093170John Hoford            }
2045abb7d134c02ac60091108c491dafb00877093170John Hoford            double disc = 1.0 / dsq - 1.0 / 4.0;
2046abb7d134c02ac60091108c491dafb00877093170John Hoford            if (disc < 0.0) {
2047abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.w(LOGTAG, "Points are too far apart " + dsq);
2048abb7d134c02ac60091108c491dafb00877093170John Hoford                float adjust = (float) (Math.sqrt(dsq) / 1.99999);
2049abb7d134c02ac60091108c491dafb00877093170John Hoford                drawArc(p, x0, y0, x1, y1, a * adjust,
2050abb7d134c02ac60091108c491dafb00877093170John Hoford                        b * adjust, theta, isMoreThanHalf, isPositiveArc);
2051abb7d134c02ac60091108c491dafb00877093170John Hoford                return; /* Points are too far apart */
2052abb7d134c02ac60091108c491dafb00877093170John Hoford            }
2053abb7d134c02ac60091108c491dafb00877093170John Hoford            double s = Math.sqrt(disc);
2054abb7d134c02ac60091108c491dafb00877093170John Hoford            double sdx = s * dx;
2055abb7d134c02ac60091108c491dafb00877093170John Hoford            double sdy = s * dy;
2056abb7d134c02ac60091108c491dafb00877093170John Hoford            double cx;
2057abb7d134c02ac60091108c491dafb00877093170John Hoford            double cy;
2058abb7d134c02ac60091108c491dafb00877093170John Hoford            if (isMoreThanHalf == isPositiveArc) {
2059abb7d134c02ac60091108c491dafb00877093170John Hoford                cx = xm - sdy;
2060abb7d134c02ac60091108c491dafb00877093170John Hoford                cy = ym + sdx;
2061abb7d134c02ac60091108c491dafb00877093170John Hoford            } else {
2062abb7d134c02ac60091108c491dafb00877093170John Hoford                cx = xm + sdy;
2063abb7d134c02ac60091108c491dafb00877093170John Hoford                cy = ym - sdx;
2064abb7d134c02ac60091108c491dafb00877093170John Hoford            }
2065abb7d134c02ac60091108c491dafb00877093170John Hoford
2066abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta0 = Math.atan2((y0p - cy), (x0p - cx));
2067abb7d134c02ac60091108c491dafb00877093170John Hoford
2068abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta1 = Math.atan2((y1p - cy), (x1p - cx));
2069abb7d134c02ac60091108c491dafb00877093170John Hoford
2070abb7d134c02ac60091108c491dafb00877093170John Hoford            double sweep = (eta1 - eta0);
2071abb7d134c02ac60091108c491dafb00877093170John Hoford            if (isPositiveArc != (sweep >= 0)) {
2072abb7d134c02ac60091108c491dafb00877093170John Hoford                if (sweep > 0) {
2073abb7d134c02ac60091108c491dafb00877093170John Hoford                    sweep -= 2 * Math.PI;
2074abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
2075abb7d134c02ac60091108c491dafb00877093170John Hoford                    sweep += 2 * Math.PI;
2076abb7d134c02ac60091108c491dafb00877093170John Hoford                }
2077abb7d134c02ac60091108c491dafb00877093170John Hoford            }
2078abb7d134c02ac60091108c491dafb00877093170John Hoford
2079abb7d134c02ac60091108c491dafb00877093170John Hoford            cx *= a;
2080abb7d134c02ac60091108c491dafb00877093170John Hoford            cy *= b;
2081abb7d134c02ac60091108c491dafb00877093170John Hoford            double tcx = cx;
2082abb7d134c02ac60091108c491dafb00877093170John Hoford            cx = cx * cosTheta - cy * sinTheta;
2083abb7d134c02ac60091108c491dafb00877093170John Hoford            cy = tcx * sinTheta + cy * cosTheta;
2084abb7d134c02ac60091108c491dafb00877093170John Hoford
2085abb7d134c02ac60091108c491dafb00877093170John Hoford            arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep);
2086abb7d134c02ac60091108c491dafb00877093170John Hoford        }
2087abb7d134c02ac60091108c491dafb00877093170John Hoford
2088abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
2089abb7d134c02ac60091108c491dafb00877093170John Hoford         * Converts an arc to cubic Bezier segments and records them in p.
2090abb7d134c02ac60091108c491dafb00877093170John Hoford         *
2091abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param p The target for the cubic Bezier segments
2092abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param cx The x coordinate center of the ellipse
2093abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param cy The y coordinate center of the ellipse
2094abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param a The radius of the ellipse in the horizontal direction
2095abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param b The radius of the ellipse in the vertical direction
2096abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param e1x E(eta1) x coordinate of the starting point of the arc
2097abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param e1y E(eta2) y coordinate of the starting point of the arc
2098abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param theta The angle that the ellipse bounding rectangle makes with horizontal plane
2099abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param start The start angle of the arc on the ellipse
2100abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse
2101abb7d134c02ac60091108c491dafb00877093170John Hoford         */
2102abb7d134c02ac60091108c491dafb00877093170John Hoford        private static void arcToBezier(Path p,
2103abb7d134c02ac60091108c491dafb00877093170John Hoford                double cx,
2104abb7d134c02ac60091108c491dafb00877093170John Hoford                double cy,
2105abb7d134c02ac60091108c491dafb00877093170John Hoford                double a,
2106abb7d134c02ac60091108c491dafb00877093170John Hoford                double b,
2107abb7d134c02ac60091108c491dafb00877093170John Hoford                double e1x,
2108abb7d134c02ac60091108c491dafb00877093170John Hoford                double e1y,
2109abb7d134c02ac60091108c491dafb00877093170John Hoford                double theta,
2110abb7d134c02ac60091108c491dafb00877093170John Hoford                double start,
2111abb7d134c02ac60091108c491dafb00877093170John Hoford                double sweep) {
2112abb7d134c02ac60091108c491dafb00877093170John Hoford            // Taken from equations at: http://spaceroots.org/documents/ellipse/node8.html
2113abb7d134c02ac60091108c491dafb00877093170John Hoford            // and http://www.spaceroots.org/documents/ellipse/node22.html
2114abb7d134c02ac60091108c491dafb00877093170John Hoford
2115abb7d134c02ac60091108c491dafb00877093170John Hoford            // Maximum of 45 degrees per cubic Bezier segment
2116abb7d134c02ac60091108c491dafb00877093170John Hoford            int numSegments = Math.abs((int) Math.ceil(sweep * 4 / Math.PI));
2117abb7d134c02ac60091108c491dafb00877093170John Hoford
2118abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta1 = start;
2119abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosTheta = Math.cos(theta);
2120abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinTheta = Math.sin(theta);
2121abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosEta1 = Math.cos(eta1);
2122abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinEta1 = Math.sin(eta1);
2123abb7d134c02ac60091108c491dafb00877093170John Hoford            double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1);
2124abb7d134c02ac60091108c491dafb00877093170John Hoford            double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1);
2125abb7d134c02ac60091108c491dafb00877093170John Hoford
2126abb7d134c02ac60091108c491dafb00877093170John Hoford            double anglePerSegment = sweep / numSegments;
2127abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < numSegments; i++) {
2128abb7d134c02ac60091108c491dafb00877093170John Hoford                double eta2 = eta1 + anglePerSegment;
2129abb7d134c02ac60091108c491dafb00877093170John Hoford                double sinEta2 = Math.sin(eta2);
2130abb7d134c02ac60091108c491dafb00877093170John Hoford                double cosEta2 = Math.cos(eta2);
2131abb7d134c02ac60091108c491dafb00877093170John Hoford                double e2x = cx + (a * cosTheta * cosEta2) - (b * sinTheta * sinEta2);
2132abb7d134c02ac60091108c491dafb00877093170John Hoford                double e2y = cy + (a * sinTheta * cosEta2) + (b * cosTheta * sinEta2);
2133abb7d134c02ac60091108c491dafb00877093170John Hoford                double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2;
2134abb7d134c02ac60091108c491dafb00877093170John Hoford                double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2;
2135abb7d134c02ac60091108c491dafb00877093170John Hoford                double tanDiff2 = Math.tan((eta2 - eta1) / 2);
2136abb7d134c02ac60091108c491dafb00877093170John Hoford                double alpha =
2137abb7d134c02ac60091108c491dafb00877093170John Hoford                        Math.sin(eta2 - eta1) * (Math.sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3;
2138abb7d134c02ac60091108c491dafb00877093170John Hoford                double q1x = e1x + alpha * ep1x;
2139abb7d134c02ac60091108c491dafb00877093170John Hoford                double q1y = e1y + alpha * ep1y;
2140abb7d134c02ac60091108c491dafb00877093170John Hoford                double q2x = e2x - alpha * ep2x;
2141abb7d134c02ac60091108c491dafb00877093170John Hoford                double q2y = e2y - alpha * ep2y;
2142abb7d134c02ac60091108c491dafb00877093170John Hoford
2143abb7d134c02ac60091108c491dafb00877093170John Hoford                p.cubicTo((float) q1x,
2144abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q1y,
2145abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q2x,
2146abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q2y,
2147abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) e2x,
2148abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) e2y);
2149abb7d134c02ac60091108c491dafb00877093170John Hoford                eta1 = eta2;
2150abb7d134c02ac60091108c491dafb00877093170John Hoford                e1x = e2x;
2151abb7d134c02ac60091108c491dafb00877093170John Hoford                e1y = e2y;
2152abb7d134c02ac60091108c491dafb00877093170John Hoford                ep1x = ep2x;
2153abb7d134c02ac60091108c491dafb00877093170John Hoford                ep1y = ep2y;
2154abb7d134c02ac60091108c491dafb00877093170John Hoford            }
2155abb7d134c02ac60091108c491dafb00877093170John Hoford        }
2156abb7d134c02ac60091108c491dafb00877093170John Hoford
2157abb7d134c02ac60091108c491dafb00877093170John Hoford    }
2158abb7d134c02ac60091108c491dafb00877093170John Hoford}
2159