VectorDrawable.java revision 7f1ab7a43fd7e65bbd7460334014ecc73dbb1b8d
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    @Override
203abb7d134c02ac60091108c491dafb00877093170John Hoford    public ConstantState getConstantState() {
204abb7d134c02ac60091108c491dafb00877093170John Hoford        return mVectorState;
205abb7d134c02ac60091108c491dafb00877093170John Hoford    }
206abb7d134c02ac60091108c491dafb00877093170John Hoford
207abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
2085c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * Starts the animation.
209abb7d134c02ac60091108c491dafb00877093170John Hoford     */
210abb7d134c02ac60091108c491dafb00877093170John Hoford    public void start() {
211abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mBasicAnimator.start();
212abb7d134c02ac60091108c491dafb00877093170John Hoford    }
213abb7d134c02ac60091108c491dafb00877093170John Hoford
214abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
2155c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * Stops the animation.
216abb7d134c02ac60091108c491dafb00877093170John Hoford     */
217abb7d134c02ac60091108c491dafb00877093170John Hoford    public void stop() {
218abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mBasicAnimator.end();
219abb7d134c02ac60091108c491dafb00877093170John Hoford    }
220abb7d134c02ac60091108c491dafb00877093170John Hoford
221abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
2225c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * Returns the current completion value for the animation.
223abb7d134c02ac60091108c491dafb00877093170John Hoford     *
2245c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * @return the current point on the animation, typically between 0 and 1
225abb7d134c02ac60091108c491dafb00877093170John Hoford     */
226abb7d134c02ac60091108c491dafb00877093170John Hoford    public float geAnimationFraction() {
227abb7d134c02ac60091108c491dafb00877093170John Hoford        return mVectorState.mVAnimatedPath.getValue();
228abb7d134c02ac60091108c491dafb00877093170John Hoford    }
229abb7d134c02ac60091108c491dafb00877093170John Hoford
230abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
2315c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * Set the current completion value for the animation.
232abb7d134c02ac60091108c491dafb00877093170John Hoford     *
2335c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * @param value the point along the animation, typically between 0 and 1
234abb7d134c02ac60091108c491dafb00877093170John Hoford     */
235abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setAnimationFraction(float value) {
236abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mVAnimatedPath.setAnimationFraction(value);
237abb7d134c02ac60091108c491dafb00877093170John Hoford        invalidateSelf();
238abb7d134c02ac60091108c491dafb00877093170John Hoford    }
239abb7d134c02ac60091108c491dafb00877093170John Hoford
240abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
241abb7d134c02ac60091108c491dafb00877093170John Hoford     * set the amount of time the animation will take
242abb7d134c02ac60091108c491dafb00877093170John Hoford     *
243abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param duration amount of time in milliseconds
244abb7d134c02ac60091108c491dafb00877093170John Hoford     */
245abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setDuration(long duration) {
246abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mBasicAnimator.setDuration(duration);
247abb7d134c02ac60091108c491dafb00877093170John Hoford    }
248abb7d134c02ac60091108c491dafb00877093170John Hoford
249abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
2505c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * Defines what this animation should do when it reaches the end. This
2515c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * setting is applied only when the repeat count is either greater than
2525c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * 0 or {@link ValueAnimator#INFINITE}.
2535c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     *
2545c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * @param mode the animation mode, either {@link ValueAnimator#RESTART}
2555c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     *        or {@link ValueAnimator#REVERSE}
256abb7d134c02ac60091108c491dafb00877093170John Hoford     */
257abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setRepeatMode(int mode) {
258abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mBasicAnimator.setRepeatMode(mode);
259abb7d134c02ac60091108c491dafb00877093170John Hoford    }
260abb7d134c02ac60091108c491dafb00877093170John Hoford
261abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
262abb7d134c02ac60091108c491dafb00877093170John Hoford     * Sets animation to repeat
263abb7d134c02ac60091108c491dafb00877093170John Hoford     *
264abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param repeat True if this drawable repeats its animation
265abb7d134c02ac60091108c491dafb00877093170John Hoford     */
266abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setRepeatCount(int repeat) {
267abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mBasicAnimator.setRepeatCount(repeat);
268abb7d134c02ac60091108c491dafb00877093170John Hoford    }
269abb7d134c02ac60091108c491dafb00877093170John Hoford
270abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
2715c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * @return the animation repeat count, either a value greater than 0 or
2725c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     *         {@link ValueAnimator#INFINITE}
273abb7d134c02ac60091108c491dafb00877093170John Hoford     */
274abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getRepeatCount() {
275abb7d134c02ac60091108c491dafb00877093170John Hoford        return mVectorState.mBasicAnimator.getRepeatCount();
276abb7d134c02ac60091108c491dafb00877093170John Hoford    }
277abb7d134c02ac60091108c491dafb00877093170John Hoford
278abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
279abb7d134c02ac60091108c491dafb00877093170John Hoford    public boolean isStateful() {
280abb7d134c02ac60091108c491dafb00877093170John Hoford        return true;
281abb7d134c02ac60091108c491dafb00877093170John Hoford    }
282abb7d134c02ac60091108c491dafb00877093170John Hoford
283abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
284abb7d134c02ac60091108c491dafb00877093170John Hoford    protected boolean onStateChange(int[] state) {
285abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mVAnimatedPath.setState(state);
286abb7d134c02ac60091108c491dafb00877093170John Hoford        int direction = mVectorState.mVAnimatedPath.getTrigger(state);
287abb7d134c02ac60091108c491dafb00877093170John Hoford        if (direction>0) {
288abb7d134c02ac60091108c491dafb00877093170John Hoford            animateForward();
289abb7d134c02ac60091108c491dafb00877093170John Hoford        } else if (direction<0) {
290abb7d134c02ac60091108c491dafb00877093170John Hoford            animateBackward();
291abb7d134c02ac60091108c491dafb00877093170John Hoford        }
292abb7d134c02ac60091108c491dafb00877093170John Hoford        super.onStateChange(state);
293abb7d134c02ac60091108c491dafb00877093170John Hoford        invalidateSelf();
294abb7d134c02ac60091108c491dafb00877093170John Hoford        return true;
295abb7d134c02ac60091108c491dafb00877093170John Hoford    }
296abb7d134c02ac60091108c491dafb00877093170John Hoford
297abb7d134c02ac60091108c491dafb00877093170John Hoford    private void animateForward(){
298abb7d134c02ac60091108c491dafb00877093170John Hoford        if (!mVectorState.mBasicAnimator.isStarted()) {
299abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mBasicAnimator.setFloatValues(0,1);
300abb7d134c02ac60091108c491dafb00877093170John Hoford            start();
301abb7d134c02ac60091108c491dafb00877093170John Hoford        }
302abb7d134c02ac60091108c491dafb00877093170John Hoford    }
303abb7d134c02ac60091108c491dafb00877093170John Hoford
304abb7d134c02ac60091108c491dafb00877093170John Hoford    private void animateBackward(){
305abb7d134c02ac60091108c491dafb00877093170John Hoford        if (!mVectorState.mBasicAnimator.isStarted()) {
306abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mBasicAnimator.setFloatValues(.99f,0);
307abb7d134c02ac60091108c491dafb00877093170John Hoford            start();
308abb7d134c02ac60091108c491dafb00877093170John Hoford        }
309abb7d134c02ac60091108c491dafb00877093170John Hoford    }
310abb7d134c02ac60091108c491dafb00877093170John Hoford
311abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
312abb7d134c02ac60091108c491dafb00877093170John Hoford    public void draw(Canvas canvas) {
313abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mVAnimatedPath.draw(canvas);
314abb7d134c02ac60091108c491dafb00877093170John Hoford    }
315abb7d134c02ac60091108c491dafb00877093170John Hoford
316abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
317abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setAlpha(int alpha) {
318abb7d134c02ac60091108c491dafb00877093170John Hoford        // TODO correct handling of transparent
319abb7d134c02ac60091108c491dafb00877093170John Hoford        if (mAlpha != alpha) {
320abb7d134c02ac60091108c491dafb00877093170John Hoford            mAlpha = alpha;
321abb7d134c02ac60091108c491dafb00877093170John Hoford            invalidateSelf();
322abb7d134c02ac60091108c491dafb00877093170John Hoford        }
323abb7d134c02ac60091108c491dafb00877093170John Hoford    }
324abb7d134c02ac60091108c491dafb00877093170John Hoford
325abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
326abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setColorFilter(ColorFilter colorFilter) {
327abb7d134c02ac60091108c491dafb00877093170John Hoford        // TODO: support color filter
328abb7d134c02ac60091108c491dafb00877093170John Hoford    }
329abb7d134c02ac60091108c491dafb00877093170John Hoford
330abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
331abb7d134c02ac60091108c491dafb00877093170John Hoford     * Returns a {@link android.graphics.PixelFormat graphics.PixelFormat}
332abb7d134c02ac60091108c491dafb00877093170John Hoford     * value of TRANSLUCENT.
333abb7d134c02ac60091108c491dafb00877093170John Hoford     */
334abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
335abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getOpacity() {
336abb7d134c02ac60091108c491dafb00877093170John Hoford        return PixelFormat.TRANSLUCENT;
337abb7d134c02ac60091108c491dafb00877093170John Hoford    }
338abb7d134c02ac60091108c491dafb00877093170John Hoford
339abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
340abb7d134c02ac60091108c491dafb00877093170John Hoford     * Sets padding for this shape, defined by a Rect object. Define the padding in the Rect object
341abb7d134c02ac60091108c491dafb00877093170John Hoford     * as: left, top, right, bottom.
342abb7d134c02ac60091108c491dafb00877093170John Hoford     */
343abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setPadding(Rect padding) {
344abb7d134c02ac60091108c491dafb00877093170John Hoford        setPadding(padding.left, padding.top, padding.right, padding.bottom);
345abb7d134c02ac60091108c491dafb00877093170John Hoford    }
346abb7d134c02ac60091108c491dafb00877093170John Hoford
347abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
348abb7d134c02ac60091108c491dafb00877093170John Hoford     * Sets padding for the shape.
349abb7d134c02ac60091108c491dafb00877093170John Hoford     *
350abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param left padding for the left side (in pixels)
351abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param top padding for the top (in pixels)
352abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param right padding for the right side (in pixels)
353abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param bottom padding for the bottom (in pixels)
354abb7d134c02ac60091108c491dafb00877093170John Hoford     */
355abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setPadding(int left, int top, int right, int bottom) {
356abb7d134c02ac60091108c491dafb00877093170John Hoford        if ((left | top | right | bottom) == 0) {
357abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mPadding = null;
358abb7d134c02ac60091108c491dafb00877093170John Hoford        } else {
359abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mVectorState.mPadding == null) {
360abb7d134c02ac60091108c491dafb00877093170John Hoford                mVectorState.mPadding = new Rect();
361abb7d134c02ac60091108c491dafb00877093170John Hoford            }
362abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mPadding.set(left, top, right, bottom);
363abb7d134c02ac60091108c491dafb00877093170John Hoford        }
364abb7d134c02ac60091108c491dafb00877093170John Hoford        invalidateSelf();
365abb7d134c02ac60091108c491dafb00877093170John Hoford    }
366abb7d134c02ac60091108c491dafb00877093170John Hoford
367abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
368abb7d134c02ac60091108c491dafb00877093170John Hoford     * Sets the intrinsic (default) width for this shape.
369abb7d134c02ac60091108c491dafb00877093170John Hoford     *
370abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param width the intrinsic width (in pixels)
371abb7d134c02ac60091108c491dafb00877093170John Hoford     */
372abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setIntrinsicWidth(int width) {
373abb7d134c02ac60091108c491dafb00877093170John Hoford        if (mVectorState.mIntrinsicWidth != width) {
374abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mIntrinsicWidth = width;
375abb7d134c02ac60091108c491dafb00877093170John Hoford            invalidateSelf();
376abb7d134c02ac60091108c491dafb00877093170John Hoford        }
377abb7d134c02ac60091108c491dafb00877093170John Hoford    }
378abb7d134c02ac60091108c491dafb00877093170John Hoford
379abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
380abb7d134c02ac60091108c491dafb00877093170John Hoford     * Sets the intrinsic (default) height for this shape.
381abb7d134c02ac60091108c491dafb00877093170John Hoford     *
382abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param height the intrinsic height (in pixels)
383abb7d134c02ac60091108c491dafb00877093170John Hoford     */
384abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setIntrinsicHeight(int height) {
385abb7d134c02ac60091108c491dafb00877093170John Hoford        if (mVectorState.mIntrinsicHeight != height) {
386abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mIntrinsicHeight = height;
387abb7d134c02ac60091108c491dafb00877093170John Hoford            invalidateSelf();
388abb7d134c02ac60091108c491dafb00877093170John Hoford        }
389abb7d134c02ac60091108c491dafb00877093170John Hoford    }
390abb7d134c02ac60091108c491dafb00877093170John Hoford
391abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
392abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getIntrinsicWidth() {
393abb7d134c02ac60091108c491dafb00877093170John Hoford        return mVectorState.mIntrinsicWidth;
394abb7d134c02ac60091108c491dafb00877093170John Hoford    }
395abb7d134c02ac60091108c491dafb00877093170John Hoford
396abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
397abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getIntrinsicHeight() {
398abb7d134c02ac60091108c491dafb00877093170John Hoford        return mVectorState.mIntrinsicHeight;
399abb7d134c02ac60091108c491dafb00877093170John Hoford    }
400abb7d134c02ac60091108c491dafb00877093170John Hoford
401abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
402abb7d134c02ac60091108c491dafb00877093170John Hoford    public boolean getPadding(Rect padding) {
403abb7d134c02ac60091108c491dafb00877093170John Hoford        if (mVectorState.mPadding != null) {
404abb7d134c02ac60091108c491dafb00877093170John Hoford            padding.set(mVectorState.mPadding);
405abb7d134c02ac60091108c491dafb00877093170John Hoford            return true;
406abb7d134c02ac60091108c491dafb00877093170John Hoford        } else {
407abb7d134c02ac60091108c491dafb00877093170John Hoford            return super.getPadding(padding);
408abb7d134c02ac60091108c491dafb00877093170John Hoford        }
409abb7d134c02ac60091108c491dafb00877093170John Hoford    }
410abb7d134c02ac60091108c491dafb00877093170John Hoford
411abb7d134c02ac60091108c491dafb00877093170John Hoford    /** @hide */
412abb7d134c02ac60091108c491dafb00877093170John Hoford    public static VectorDrawable create(Resources resources, int rid) {
413abb7d134c02ac60091108c491dafb00877093170John Hoford        try {
414abb7d134c02ac60091108c491dafb00877093170John Hoford            VectorDrawable drawable = new VectorDrawable();
415abb7d134c02ac60091108c491dafb00877093170John Hoford            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
416abb7d134c02ac60091108c491dafb00877093170John Hoford            factory.setNamespaceAware(true);
417abb7d134c02ac60091108c491dafb00877093170John Hoford            XmlPullParser xpp = resources.getXml(rid);
418abb7d134c02ac60091108c491dafb00877093170John Hoford            AttributeSet attrs = Xml.asAttributeSet(xpp);
419abb7d134c02ac60091108c491dafb00877093170John Hoford            drawable.inflate(resources, xpp, attrs);
420abb7d134c02ac60091108c491dafb00877093170John Hoford            drawable.setAnimationFraction(0);
421abb7d134c02ac60091108c491dafb00877093170John Hoford            return drawable;
422abb7d134c02ac60091108c491dafb00877093170John Hoford        } catch (XmlPullParserException e) {
423abb7d134c02ac60091108c491dafb00877093170John Hoford            Log.e(LOGTAG, "parser error", e);
424abb7d134c02ac60091108c491dafb00877093170John Hoford        } catch (IOException e) {
425abb7d134c02ac60091108c491dafb00877093170John Hoford            Log.e(LOGTAG, "parser error", e);
426abb7d134c02ac60091108c491dafb00877093170John Hoford        }
427abb7d134c02ac60091108c491dafb00877093170John Hoford        return null;
428abb7d134c02ac60091108c491dafb00877093170John Hoford    }
429abb7d134c02ac60091108c491dafb00877093170John Hoford
430abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
431abb7d134c02ac60091108c491dafb00877093170John Hoford    public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
432abb7d134c02ac60091108c491dafb00877093170John Hoford            throws XmlPullParserException, IOException {
4339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        final VAnimatedPath p = inflateInternal(res, parser, attrs, theme);
4349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        setAnimatedPath(p);
435abb7d134c02ac60091108c491dafb00877093170John Hoford    }
436abb7d134c02ac60091108c491dafb00877093170John Hoford
4379453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    @Override
4389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    public boolean canApplyTheme() {
4399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        return super.canApplyTheme() || mVectorState != null && mVectorState.canApplyTheme();
4409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    }
4419453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
4429453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    @Override
4439453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    public void applyTheme(Theme t) {
4449453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        super.applyTheme(t);
4459453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
4469453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        final VectorDrawableState state = mVectorState;
4479453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        final VAnimatedPath path = state.mVAnimatedPath;
4489453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        if (path != null && path.canApplyTheme()) {
4499453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            path.applyTheme(t);
4509453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
4519453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    }
4529453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
4539453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    private VAnimatedPath inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
4549453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            Theme theme) throws XmlPullParserException, IOException {
4559453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        final VAnimatedPath animatedPath = new VAnimatedPath();
4569453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
457abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noSizeTag = true;
458abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noViewportTag = true;
459abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noGroupTag = true;
460abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noPathTag = true;
4619453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
4629453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        VGroup currentGroup = null;
463abb7d134c02ac60091108c491dafb00877093170John Hoford
464abb7d134c02ac60091108c491dafb00877093170John Hoford        int eventType = parser.getEventType();
465abb7d134c02ac60091108c491dafb00877093170John Hoford        while (eventType != XmlPullParser.END_DOCUMENT) {
466abb7d134c02ac60091108c491dafb00877093170John Hoford            if (eventType == XmlPullParser.START_TAG) {
4679453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final String tagName = parser.getName();
468abb7d134c02ac60091108c491dafb00877093170John Hoford                if (SHAPE_PATH.equals(tagName)) {
4699453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final VPath path = new VPath();
4709453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    path.inflate(res, attrs, theme);
4719453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    currentGroup.add(path);
472abb7d134c02ac60091108c491dafb00877093170John Hoford                    noPathTag = false;
473abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_ANIMATION.equals(tagName)) {
4749453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final VAnimation anim = new VAnimation();
4759453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    anim.inflate(animatedPath.mGroupList, res, attrs, theme);
476abb7d134c02ac60091108c491dafb00877093170John Hoford                    animatedPath.addAnimation(anim);
477abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_SIZE.equals(tagName)) {
478abb7d134c02ac60091108c491dafb00877093170John Hoford                    animatedPath.parseSize(res, attrs);
479abb7d134c02ac60091108c491dafb00877093170John Hoford                    noSizeTag = false;
480abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_VIEWPORT.equals(tagName)) {
481abb7d134c02ac60091108c491dafb00877093170John Hoford                    animatedPath.parseViewport(res, attrs);
482abb7d134c02ac60091108c491dafb00877093170John Hoford                    noViewportTag = false;
483abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_GROUP.equals(tagName)) {
4849453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    currentGroup = new VGroup();
485abb7d134c02ac60091108c491dafb00877093170John Hoford                    animatedPath.mGroupList.add(currentGroup);
486abb7d134c02ac60091108c491dafb00877093170John Hoford                    noGroupTag = false;
487abb7d134c02ac60091108c491dafb00877093170John Hoford                }  else if (SHAPE_VECTOR.equals(tagName)) {
4889453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final TypedArray a = res.obtainAttributes(attrs, R.styleable.VectorDrawable);
489abb7d134c02ac60091108c491dafb00877093170John Hoford                    animatedPath.setTrigger(a.getInteger(R.styleable.VectorDrawable_trigger, 0));
490177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui
491177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    // Parsing the version information.
492177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    // Right now, we only support version "1".
493177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    // If the xml didn't specify the version number, the default version is "1".
4949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final int versionCode = a.getInt(R.styleable.VectorDrawable_versionCode, 1);
495177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    if (versionCode != 1) {
496177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                        throw new IllegalArgumentException(
497177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                                "So far, VectorDrawable only support version 1");
498177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    }
499177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui
500abb7d134c02ac60091108c491dafb00877093170John Hoford                    a.recycle();
501abb7d134c02ac60091108c491dafb00877093170John Hoford                }
502abb7d134c02ac60091108c491dafb00877093170John Hoford            }
5039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
504abb7d134c02ac60091108c491dafb00877093170John Hoford            eventType = parser.next();
505abb7d134c02ac60091108c491dafb00877093170John Hoford        }
5069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
507abb7d134c02ac60091108c491dafb00877093170John Hoford        if (noSizeTag || noViewportTag || noGroupTag || noPathTag) {
5089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final StringBuffer tag = new StringBuffer();
5099453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
510abb7d134c02ac60091108c491dafb00877093170John Hoford            if (noSizeTag) {
5119453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_SIZE);
512abb7d134c02ac60091108c491dafb00877093170John Hoford            }
5139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
514abb7d134c02ac60091108c491dafb00877093170John Hoford            if  (noViewportTag){
515abb7d134c02ac60091108c491dafb00877093170John Hoford                if (tag.length()>0) {
516abb7d134c02ac60091108c491dafb00877093170John Hoford                    tag.append(" & ");
517abb7d134c02ac60091108c491dafb00877093170John Hoford                }
5189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_SIZE);
519abb7d134c02ac60091108c491dafb00877093170John Hoford            }
5209453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
521abb7d134c02ac60091108c491dafb00877093170John Hoford            if  (noGroupTag){
522abb7d134c02ac60091108c491dafb00877093170John Hoford                if (tag.length()>0) {
523abb7d134c02ac60091108c491dafb00877093170John Hoford                    tag.append(" & ");
524abb7d134c02ac60091108c491dafb00877093170John Hoford                }
5259453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_GROUP);
526abb7d134c02ac60091108c491dafb00877093170John Hoford            }
5279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
528abb7d134c02ac60091108c491dafb00877093170John Hoford            if  (noPathTag){
529abb7d134c02ac60091108c491dafb00877093170John Hoford                if (tag.length()>0) {
530abb7d134c02ac60091108c491dafb00877093170John Hoford                    tag.append(" or ");
531abb7d134c02ac60091108c491dafb00877093170John Hoford                }
5329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_PATH);
533abb7d134c02ac60091108c491dafb00877093170John Hoford            }
5349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
5359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            throw new XmlPullParserException("no " + tag + " defined");
536abb7d134c02ac60091108c491dafb00877093170John Hoford        }
5379453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
538abb7d134c02ac60091108c491dafb00877093170John Hoford        // post parse cleanup
539abb7d134c02ac60091108c491dafb00877093170John Hoford        animatedPath.parseFinish();
540abb7d134c02ac60091108c491dafb00877093170John Hoford        return animatedPath;
541abb7d134c02ac60091108c491dafb00877093170John Hoford    }
542abb7d134c02ac60091108c491dafb00877093170John Hoford
543abb7d134c02ac60091108c491dafb00877093170John Hoford    private void setAnimatedPath(VAnimatedPath animatedPath) {
544abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mVAnimatedPath = animatedPath;
5459453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
546abb7d134c02ac60091108c491dafb00877093170John Hoford        setIntrinsicWidth((int) mVectorState.mVAnimatedPath.mBaseWidth);
547abb7d134c02ac60091108c491dafb00877093170John Hoford        setIntrinsicHeight((int) mVectorState.mVAnimatedPath.mBaseHeight);
5489453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
549abb7d134c02ac60091108c491dafb00877093170John Hoford        long duration = mVectorState.mVAnimatedPath.getTotalAnimationDuration();
550abb7d134c02ac60091108c491dafb00877093170John Hoford        if (duration == -1) { // if it set to infinite set to 1 hour
551abb7d134c02ac60091108c491dafb00877093170John Hoford            duration = DEFAULT_INFINITE_DURATION; // TODO define correct approach for infinite
552abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mBasicAnimator.setFloatValues(0, duration / 1000);
553abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mBasicAnimator.setInterpolator(new LinearInterpolator());
554abb7d134c02ac60091108c491dafb00877093170John Hoford        }
555abb7d134c02ac60091108c491dafb00877093170John Hoford
5569453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        setDuration(duration);
557abb7d134c02ac60091108c491dafb00877093170John Hoford        setAnimationFraction(0);
558abb7d134c02ac60091108c491dafb00877093170John Hoford    }
559abb7d134c02ac60091108c491dafb00877093170John Hoford
560abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
561abb7d134c02ac60091108c491dafb00877093170John Hoford    public boolean setVisible(boolean visible, boolean restart) {
562abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean changed = super.setVisible(visible, restart);
563abb7d134c02ac60091108c491dafb00877093170John Hoford        if (visible) {
564abb7d134c02ac60091108c491dafb00877093170John Hoford            if (changed || restart) {
565abb7d134c02ac60091108c491dafb00877093170John Hoford                setAnimationFraction(0);
566abb7d134c02ac60091108c491dafb00877093170John Hoford            }
567abb7d134c02ac60091108c491dafb00877093170John Hoford        } else {
568abb7d134c02ac60091108c491dafb00877093170John Hoford            stop();
569abb7d134c02ac60091108c491dafb00877093170John Hoford        }
570abb7d134c02ac60091108c491dafb00877093170John Hoford        return changed;
571abb7d134c02ac60091108c491dafb00877093170John Hoford    }
572abb7d134c02ac60091108c491dafb00877093170John Hoford
5735c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette    private static class VectorDrawableState extends ConstantState {
5745c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        int mChangingConfigurations;
5755c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        ValueAnimator mBasicAnimator;
5765c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        VAnimatedPath mVAnimatedPath;
5775c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        Rect mPadding;
5785c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        int mIntrinsicHeight;
5795c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        int mIntrinsicWidth;
5805c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
5815c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public VectorDrawableState(VectorDrawableState copy) {
5825c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            if (copy != null) {
5835c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mChangingConfigurations = copy.mChangingConfigurations;
5845c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mVAnimatedPath = new VAnimatedPath(copy.mVAnimatedPath);
5855c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mPadding = new Rect(copy.mPadding);
5865c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mIntrinsicHeight = copy.mIntrinsicHeight;
5875c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mIntrinsicWidth = copy.mIntrinsicWidth;
5885c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            } else {
5895c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mVAnimatedPath = new VAnimatedPath();
5905c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            }
5915c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
5925c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
5935c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
5945c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable() {
5955c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, null, null);
5965c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
5975c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
5985c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
5995c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable(Resources res) {
6005c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, res, null);
6015c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
6025c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
6035c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
6045c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable(Resources res, Theme theme) {
6055c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, res, theme);
6065c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
6075c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
6085c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
6095c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public int getChangingConfigurations() {
6105c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return mChangingConfigurations;
6115c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
6125c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette    }
6135c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
614abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VAnimatedPath {
615abb7d134c02ac60091108c491dafb00877093170John Hoford        private ArrayList<VAnimation> mCurrentAnimList = null;
616abb7d134c02ac60091108c491dafb00877093170John Hoford        private VPath[] mCurrentPaths;
617abb7d134c02ac60091108c491dafb00877093170John Hoford        private float mAnimationValue = 0; // value goes from 0 to 1
618abb7d134c02ac60091108c491dafb00877093170John Hoford        private Paint mStrokePaint = null;
619abb7d134c02ac60091108c491dafb00877093170John Hoford        private Paint mFillPaint = null;
620abb7d134c02ac60091108c491dafb00877093170John Hoford        private PathMeasure mPathMeasure;
621abb7d134c02ac60091108c491dafb00877093170John Hoford        private Path mPath = new Path();
622abb7d134c02ac60091108c491dafb00877093170John Hoford        private Path mRenderPath = new Path();
623abb7d134c02ac60091108c491dafb00877093170John Hoford        private Matrix mMatrix = new Matrix();
624abb7d134c02ac60091108c491dafb00877093170John Hoford        private long mTotalDuration;
625abb7d134c02ac60091108c491dafb00877093170John Hoford        private int[] mCurrentState = new int[0];
626abb7d134c02ac60091108c491dafb00877093170John Hoford        private int mTrigger;
627abb7d134c02ac60091108c491dafb00877093170John Hoford        private boolean mTriggerState;
6289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6299453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        final ArrayList<VGroup> mGroupList = new ArrayList<VGroup>();
6309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
631abb7d134c02ac60091108c491dafb00877093170John Hoford        float mBaseWidth = 1;
632abb7d134c02ac60091108c491dafb00877093170John Hoford        float mBaseHeight = 1;
633abb7d134c02ac60091108c491dafb00877093170John Hoford        float mViewportWidth;
634abb7d134c02ac60091108c491dafb00877093170John Hoford        float mViewportHeight;
635abb7d134c02ac60091108c491dafb00877093170John Hoford
636abb7d134c02ac60091108c491dafb00877093170John Hoford        public VAnimatedPath() {
637abb7d134c02ac60091108c491dafb00877093170John Hoford            setup();
638abb7d134c02ac60091108c491dafb00877093170John Hoford        }
6399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
640abb7d134c02ac60091108c491dafb00877093170John Hoford        public VAnimatedPath(VAnimatedPath copy) {
641abb7d134c02ac60091108c491dafb00877093170John Hoford            setup();
642abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentAnimList = new ArrayList<VAnimation>(copy.mCurrentAnimList);
6439453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            mGroupList.addAll(copy.mGroupList);
644abb7d134c02ac60091108c491dafb00877093170John Hoford            if (copy.mCurrentPaths != null) {
645abb7d134c02ac60091108c491dafb00877093170John Hoford                mCurrentPaths = new VPath[copy.mCurrentPaths.length];
646abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int i = 0; i < mCurrentPaths.length; i++) {
647abb7d134c02ac60091108c491dafb00877093170John Hoford                    mCurrentPaths[i] = new VPath(copy.mCurrentPaths[i]);
648abb7d134c02ac60091108c491dafb00877093170John Hoford                }
649abb7d134c02ac60091108c491dafb00877093170John Hoford            }
650abb7d134c02ac60091108c491dafb00877093170John Hoford            mAnimationValue = copy.mAnimationValue; // time goes from 0 to 1
651abb7d134c02ac60091108c491dafb00877093170John Hoford
652abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseWidth = copy.mBaseWidth;
653abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseHeight = copy.mBaseHeight;
654abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportWidth = copy.mViewportHeight;
655abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportHeight = copy.mViewportHeight;
656abb7d134c02ac60091108c491dafb00877093170John Hoford            mTotalDuration = copy.mTotalDuration;
657abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrigger = copy.mTrigger;
658abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentState = new int[0];
659abb7d134c02ac60091108c491dafb00877093170John Hoford        }
660abb7d134c02ac60091108c491dafb00877093170John Hoford
6619453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean canApplyTheme() {
6629453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final ArrayList<VGroup> groups = mGroupList;
6639453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            for (int i = groups.size() - 1; i >= 0; i--) {
6649453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final ArrayList<VPath> paths = groups.get(i).mVGList;
6659453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                for (int j = paths.size() - 1; j >= 0; j--) {
6669453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final VPath path = paths.get(j);
6679453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    if (path.canApplyTheme()) {
6689453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                        return true;
6699453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    }
6709453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
6719453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
6729453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6739453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final ArrayList<VAnimation> anims = mCurrentAnimList;
6749453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            for (int i = anims.size() - 1; i >= 0; i--) {
6759453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final VAnimation anim = anims.get(i);
6769453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                if (anim.canApplyTheme()) {
6779453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    return true;
6789453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
6799453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
6809453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6819453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return false;
6829453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
6839453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6849453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void applyTheme(Theme t) {
6859453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final ArrayList<VGroup> groups = mGroupList;
6869453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            for (int i = groups.size() - 1; i >= 0; i--) {
6879453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final ArrayList<VPath> paths = groups.get(i).mVGList;
6889453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                for (int j = paths.size() - 1; j >= 0; j--) {
6899453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final VPath path = paths.get(j);
6909453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    if (path.canApplyTheme()) {
6919453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                        path.applyTheme(t);
6929453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    }
6939453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
6949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
6959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6969453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final ArrayList<VAnimation> anims = mCurrentAnimList;
6979453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            for (int i = anims.size() - 1; i >= 0; i--) {
6989453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final VAnimation anim = anims.get(i);
6999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                if (anim.canApplyTheme()) {
7009453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    anim.applyTheme(t);
7019453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
7029453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
7039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
7049453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
705abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setTrigger(int trigger){
7069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int [] lut = {
7079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    0,
708abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.attr.state_pressed,
709abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.attr.state_focused,
710abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.attr.state_hovered,
711abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.attr.state_selected,
712abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.attr.state_checkable,
713abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.attr.state_checked,
714abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.attr.state_activated,
715abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.attr.state_focused
716abb7d134c02ac60091108c491dafb00877093170John Hoford            };
7179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
718abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrigger = lut[trigger];
719abb7d134c02ac60091108c491dafb00877093170John Hoford         }
720abb7d134c02ac60091108c491dafb00877093170John Hoford
721abb7d134c02ac60091108c491dafb00877093170John Hoford        private void setup(){
722abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokePaint = new Paint();
723abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokePaint.setStyle(Paint.Style.STROKE);
724abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokePaint.setAntiAlias(true);
725abb7d134c02ac60091108c491dafb00877093170John Hoford            mFillPaint = new Paint();
726abb7d134c02ac60091108c491dafb00877093170John Hoford            mFillPaint.setStyle(Paint.Style.FILL);
727abb7d134c02ac60091108c491dafb00877093170John Hoford            mFillPaint.setAntiAlias(true);
728abb7d134c02ac60091108c491dafb00877093170John Hoford        }
729abb7d134c02ac60091108c491dafb00877093170John Hoford
730abb7d134c02ac60091108c491dafb00877093170John Hoford        public long getTotalAnimationDuration() {
731abb7d134c02ac60091108c491dafb00877093170John Hoford            mTotalDuration = 0;
732abb7d134c02ac60091108c491dafb00877093170John Hoford            int size = mCurrentAnimList.size();
733abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < size; i++) {
734abb7d134c02ac60091108c491dafb00877093170John Hoford                VAnimation vAnimation = mCurrentAnimList.get(i);
735abb7d134c02ac60091108c491dafb00877093170John Hoford                long t = vAnimation.getTotalDuration();
736abb7d134c02ac60091108c491dafb00877093170John Hoford                if (t == -1) {
737abb7d134c02ac60091108c491dafb00877093170John Hoford                    mTotalDuration = -1;
738abb7d134c02ac60091108c491dafb00877093170John Hoford                    return -1;
739abb7d134c02ac60091108c491dafb00877093170John Hoford                }
740abb7d134c02ac60091108c491dafb00877093170John Hoford                mTotalDuration = Math.max(mTotalDuration, t);
741abb7d134c02ac60091108c491dafb00877093170John Hoford            }
742abb7d134c02ac60091108c491dafb00877093170John Hoford
743abb7d134c02ac60091108c491dafb00877093170John Hoford            return mTotalDuration;
744abb7d134c02ac60091108c491dafb00877093170John Hoford        }
745abb7d134c02ac60091108c491dafb00877093170John Hoford
746abb7d134c02ac60091108c491dafb00877093170John Hoford        public float getValue() {
747abb7d134c02ac60091108c491dafb00877093170John Hoford            return mAnimationValue;
748abb7d134c02ac60091108c491dafb00877093170John Hoford        }
749abb7d134c02ac60091108c491dafb00877093170John Hoford
750abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
751abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param value the point along the animations to show typically between 0.0f and 1.0f
752abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return true if you need to keep repeating
753abb7d134c02ac60091108c491dafb00877093170John Hoford         */
754abb7d134c02ac60091108c491dafb00877093170John Hoford        public boolean setAnimationFraction(float value) {
755abb7d134c02ac60091108c491dafb00877093170John Hoford            getTotalAnimationDuration();
7569453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
757abb7d134c02ac60091108c491dafb00877093170John Hoford            long animationTime = (long) (value * mTotalDuration);
758abb7d134c02ac60091108c491dafb00877093170John Hoford
7599453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int len = mCurrentPaths.length;
760abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < len; i++) {
761abb7d134c02ac60091108c491dafb00877093170John Hoford                animationTime =
762abb7d134c02ac60091108c491dafb00877093170John Hoford                        (long) ((mTotalDuration == -1) ? value * 1000 : mTotalDuration * value);
7639453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7649453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final VPath path = mCurrentPaths[i];
7659453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final int size = mCurrentAnimList.size();
766abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int j = 0; j < size; j++) {
7679453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final VAnimation vAnimation = mCurrentAnimList.get(j);
768abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (vAnimation.doesAdjustPath(path)) {
769abb7d134c02ac60091108c491dafb00877093170John Hoford                        mCurrentPaths[i] =  vAnimation.getPathAtTime(animationTime, path);
770abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
771abb7d134c02ac60091108c491dafb00877093170John Hoford                }
772abb7d134c02ac60091108c491dafb00877093170John Hoford            }
7739453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7749453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            mAnimationValue = value;
7759453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
776abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mTotalDuration == -1) {
777abb7d134c02ac60091108c491dafb00877093170John Hoford                return true;
778abb7d134c02ac60091108c491dafb00877093170John Hoford            } else {
779abb7d134c02ac60091108c491dafb00877093170John Hoford                return animationTime < mTotalDuration;
780abb7d134c02ac60091108c491dafb00877093170John Hoford            }
781abb7d134c02ac60091108c491dafb00877093170John Hoford        }
782abb7d134c02ac60091108c491dafb00877093170John Hoford
783abb7d134c02ac60091108c491dafb00877093170John Hoford        public void draw(Canvas canvas) {
784abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mCurrentPaths == null) {
785abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.e(LOGTAG,"mCurrentPaths == null");
786abb7d134c02ac60091108c491dafb00877093170John Hoford                return;
787abb7d134c02ac60091108c491dafb00877093170John Hoford            }
788abb7d134c02ac60091108c491dafb00877093170John Hoford
7899453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            // TODO: This should probably use getBounds().
7909453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int w = canvas.getWidth();
7919453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int h = canvas.getHeight();
7929453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
793abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mCurrentPaths.length; i++) {
794abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mCurrentPaths[i] != null && mCurrentPaths[i].isVisible(mCurrentState)) {
795abb7d134c02ac60091108c491dafb00877093170John Hoford                    drawPath(mCurrentPaths[i], canvas, w, h);
796abb7d134c02ac60091108c491dafb00877093170John Hoford                }
797abb7d134c02ac60091108c491dafb00877093170John Hoford            }
798abb7d134c02ac60091108c491dafb00877093170John Hoford        }
799abb7d134c02ac60091108c491dafb00877093170John Hoford
800abb7d134c02ac60091108c491dafb00877093170John Hoford        private void drawPath(VPath vPath, Canvas canvas, int w, int h) {
8019453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final float scale = Math.min(h / mViewportHeight, w / mViewportWidth);
802abb7d134c02ac60091108c491dafb00877093170John Hoford
803abb7d134c02ac60091108c491dafb00877093170John Hoford            vPath.toPath(mPath);
804abb7d134c02ac60091108c491dafb00877093170John Hoford            Path path = mPath;
805abb7d134c02ac60091108c491dafb00877093170John Hoford
806abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mTrimPathStart != 0.0f || vPath.mTrimPathEnd != 1.0f) {
807abb7d134c02ac60091108c491dafb00877093170John Hoford                float start = (vPath.mTrimPathStart + vPath.mTrimPathOffset) % 1.0f;
808abb7d134c02ac60091108c491dafb00877093170John Hoford                float end = (vPath.mTrimPathEnd + vPath.mTrimPathOffset) % 1.0f;
809abb7d134c02ac60091108c491dafb00877093170John Hoford
810abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPathMeasure == null) {
811abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure = new PathMeasure();
812abb7d134c02ac60091108c491dafb00877093170John Hoford                }
813abb7d134c02ac60091108c491dafb00877093170John Hoford                mPathMeasure.setPath(mPath, false);
814abb7d134c02ac60091108c491dafb00877093170John Hoford
815abb7d134c02ac60091108c491dafb00877093170John Hoford                float len = mPathMeasure.getLength();
816abb7d134c02ac60091108c491dafb00877093170John Hoford                start = start * len;
817abb7d134c02ac60091108c491dafb00877093170John Hoford                end = end * len;
818abb7d134c02ac60091108c491dafb00877093170John Hoford                path.reset();
819abb7d134c02ac60091108c491dafb00877093170John Hoford                if (start > end) {
820abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure.getSegment(start, len, path, true);
821abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure.getSegment(0f, end, path, true);
822abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
823abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure.getSegment(start, end, path, true);
824abb7d134c02ac60091108c491dafb00877093170John Hoford                }
825abb7d134c02ac60091108c491dafb00877093170John Hoford                path.rLineTo(0, 0); // fix bug in measure
826abb7d134c02ac60091108c491dafb00877093170John Hoford            }
827abb7d134c02ac60091108c491dafb00877093170John Hoford
828abb7d134c02ac60091108c491dafb00877093170John Hoford            mRenderPath.reset();
829abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.reset();
830abb7d134c02ac60091108c491dafb00877093170John Hoford
831abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.postRotate(vPath.mRotate, vPath.mPivotX, vPath.mPivotY);
832abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.postScale(scale, scale, mViewportWidth / 2f, mViewportHeight / 2f);
833abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.postTranslate(w / 2f - mViewportWidth / 2f, h / 2f - mViewportHeight / 2f);
834abb7d134c02ac60091108c491dafb00877093170John Hoford
835abb7d134c02ac60091108c491dafb00877093170John Hoford            mRenderPath.addPath(path, mMatrix);
836abb7d134c02ac60091108c491dafb00877093170John Hoford
837abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mClip) {
838abb7d134c02ac60091108c491dafb00877093170John Hoford                canvas.clipPath(mRenderPath, Region.Op.REPLACE);
839abb7d134c02ac60091108c491dafb00877093170John Hoford            }
8409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
841abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mFillColor != 0) {
842abb7d134c02ac60091108c491dafb00877093170John Hoford                mFillPaint.setColor(vPath.mFillColor);
843abb7d134c02ac60091108c491dafb00877093170John Hoford                int alpha = 0xFF & (vPath.mFillColor >> 24);
844abb7d134c02ac60091108c491dafb00877093170John Hoford                mFillPaint.setAlpha(alpha);
845abb7d134c02ac60091108c491dafb00877093170John Hoford                canvas.drawPath(mRenderPath, mFillPaint);
846abb7d134c02ac60091108c491dafb00877093170John Hoford            }
8479453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
848abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mStrokeColor != 0) {
8497f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                if (vPath.mStrokeLineJoin != null) {
8507f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    mStrokePaint.setStrokeJoin(vPath.mStrokeLineJoin);
851abb7d134c02ac60091108c491dafb00877093170John Hoford                }
8527f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                if (vPath.mStrokeLineCap != null) {
8537f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    mStrokePaint.setStrokeCap(vPath.mStrokeLineCap);
854abb7d134c02ac60091108c491dafb00877093170John Hoford                }
855abb7d134c02ac60091108c491dafb00877093170John Hoford                mStrokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale);
856abb7d134c02ac60091108c491dafb00877093170John Hoford                mStrokePaint.setColor(vPath.mStrokeColor);
857abb7d134c02ac60091108c491dafb00877093170John Hoford                mStrokePaint.setAlpha(0xFF & (vPath.mStrokeColor >> 24));
858abb7d134c02ac60091108c491dafb00877093170John Hoford                mStrokePaint.setStrokeWidth(vPath.mStrokeWidth * scale);
859abb7d134c02ac60091108c491dafb00877093170John Hoford                canvas.drawPath(mRenderPath, mStrokePaint);
860abb7d134c02ac60091108c491dafb00877093170John Hoford            }
861abb7d134c02ac60091108c491dafb00877093170John Hoford        }
862abb7d134c02ac60091108c491dafb00877093170John Hoford
863abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
864abb7d134c02ac60091108c491dafb00877093170John Hoford         * Ensure there is at least one animation for every path in group (linking them by names)
865abb7d134c02ac60091108c491dafb00877093170John Hoford         * Build the "current" path based on the first group
866abb7d134c02ac60091108c491dafb00877093170John Hoford         * TODO: improve memory use & performance or move to C++
867abb7d134c02ac60091108c491dafb00877093170John Hoford         */
868abb7d134c02ac60091108c491dafb00877093170John Hoford        public void parseFinish() {
8699453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final HashMap<String, VAnimation> newAnimations = new HashMap<String, VAnimation>();
870abb7d134c02ac60091108c491dafb00877093170John Hoford            for (VGroup group : mGroupList) {
871abb7d134c02ac60091108c491dafb00877093170John Hoford                for (VPath vPath : group.getPaths()) {
872abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (!vPath.mAnimated) {
873abb7d134c02ac60091108c491dafb00877093170John Hoford                        VAnimation ap = null;
874abb7d134c02ac60091108c491dafb00877093170John Hoford
875abb7d134c02ac60091108c491dafb00877093170John Hoford                        if (!newAnimations.containsKey(vPath.getID())) {
876abb7d134c02ac60091108c491dafb00877093170John Hoford                            newAnimations.put(vPath.getID(), ap = new VAnimation());
877abb7d134c02ac60091108c491dafb00877093170John Hoford                        } else {
878abb7d134c02ac60091108c491dafb00877093170John Hoford                            ap = newAnimations.get(vPath.getID());
879abb7d134c02ac60091108c491dafb00877093170John Hoford                        }
8809453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
881abb7d134c02ac60091108c491dafb00877093170John Hoford                        ap.addPath(vPath);
882abb7d134c02ac60091108c491dafb00877093170John Hoford                        vPath.mAnimated = true;
883abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
884abb7d134c02ac60091108c491dafb00877093170John Hoford                }
885abb7d134c02ac60091108c491dafb00877093170John Hoford            }
8869453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
887abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mCurrentAnimList == null) {
888abb7d134c02ac60091108c491dafb00877093170John Hoford                mCurrentAnimList = new ArrayList<VectorDrawable.VAnimation>();
889abb7d134c02ac60091108c491dafb00877093170John Hoford            }
890abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentAnimList.addAll(newAnimations.values());
8919453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
8929453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final Collection<VPath> paths = mGroupList.get(0).getPaths();
893abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentPaths = paths.toArray(new VPath[paths.size()]);
894abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mCurrentPaths.length; i++) {
895abb7d134c02ac60091108c491dafb00877093170John Hoford                mCurrentPaths[i] = new VPath(mCurrentPaths[i]);
896abb7d134c02ac60091108c491dafb00877093170John Hoford            }
897abb7d134c02ac60091108c491dafb00877093170John Hoford        }
898abb7d134c02ac60091108c491dafb00877093170John Hoford
899abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setState(int[] state) {
900abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentState = Arrays.copyOf(state, state.length);
901abb7d134c02ac60091108c491dafb00877093170John Hoford        }
902abb7d134c02ac60091108c491dafb00877093170John Hoford
903abb7d134c02ac60091108c491dafb00877093170John Hoford        int getTrigger(int []state){
904abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mTrigger == 0) return 0;
905abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < state.length; i++) {
906abb7d134c02ac60091108c491dafb00877093170John Hoford                if (state[i] == mTrigger){
907abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (mTriggerState)
908abb7d134c02ac60091108c491dafb00877093170John Hoford                        return 0;
909abb7d134c02ac60091108c491dafb00877093170John Hoford                    mTriggerState = true;
910abb7d134c02ac60091108c491dafb00877093170John Hoford                    return 1;
911abb7d134c02ac60091108c491dafb00877093170John Hoford                }
912abb7d134c02ac60091108c491dafb00877093170John Hoford            }
913abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mTriggerState) {
914abb7d134c02ac60091108c491dafb00877093170John Hoford                mTriggerState = false;
915abb7d134c02ac60091108c491dafb00877093170John Hoford                return -1;
916abb7d134c02ac60091108c491dafb00877093170John Hoford            }
917abb7d134c02ac60091108c491dafb00877093170John Hoford            return 0;
918abb7d134c02ac60091108c491dafb00877093170John Hoford        }
919abb7d134c02ac60091108c491dafb00877093170John Hoford
920abb7d134c02ac60091108c491dafb00877093170John Hoford        public void addAnimation(VAnimation anim) {
921abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mCurrentAnimList == null) {
922abb7d134c02ac60091108c491dafb00877093170John Hoford                mCurrentAnimList = new ArrayList<VectorDrawable.VAnimation>();
923abb7d134c02ac60091108c491dafb00877093170John Hoford            }
924abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentAnimList.add(anim);
925abb7d134c02ac60091108c491dafb00877093170John Hoford        }
926abb7d134c02ac60091108c491dafb00877093170John Hoford
927abb7d134c02ac60091108c491dafb00877093170John Hoford        private void parseViewport(Resources r, AttributeSet attrs)
928abb7d134c02ac60091108c491dafb00877093170John Hoford                throws XmlPullParserException {
929abb7d134c02ac60091108c491dafb00877093170John Hoford            TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport);
930abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportWidth = a.getFloat(R.styleable.VectorDrawableViewport_viewportWidth, 0);
931abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportHeight = a.getFloat(R.styleable.VectorDrawableViewport_viewportHeight, 0);
932abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mViewportWidth == 0 || mViewportHeight == 0) {
933abb7d134c02ac60091108c491dafb00877093170John Hoford                throw new XmlPullParserException(a.getPositionDescription()+
934abb7d134c02ac60091108c491dafb00877093170John Hoford                        "<viewport> tag requires viewportWidth & viewportHeight to be set");
935abb7d134c02ac60091108c491dafb00877093170John Hoford            }
936abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
937abb7d134c02ac60091108c491dafb00877093170John Hoford        }
938abb7d134c02ac60091108c491dafb00877093170John Hoford
939abb7d134c02ac60091108c491dafb00877093170John Hoford        private void parseSize(Resources r, AttributeSet attrs)
940abb7d134c02ac60091108c491dafb00877093170John Hoford                throws XmlPullParserException  {
941abb7d134c02ac60091108c491dafb00877093170John Hoford            TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableSize);
942abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseWidth = a.getDimension(R.styleable.VectorDrawableSize_width, 0);
943abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseHeight = a.getDimension(R.styleable.VectorDrawableSize_height, 0);
944abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mBaseWidth == 0 || mBaseHeight == 0) {
945abb7d134c02ac60091108c491dafb00877093170John Hoford                throw new XmlPullParserException(a.getPositionDescription()+
946abb7d134c02ac60091108c491dafb00877093170John Hoford                        "<size> tag requires width & height to be set");
947abb7d134c02ac60091108c491dafb00877093170John Hoford            }
948abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
949abb7d134c02ac60091108c491dafb00877093170John Hoford        }
950abb7d134c02ac60091108c491dafb00877093170John Hoford    }
951abb7d134c02ac60091108c491dafb00877093170John Hoford
952abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VAnimation {
9535c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private static final String SEPARATOR = ",";
9549453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
9555c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private static final int DIRECTION_FORWARD = 0;
9565c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private static final int DIRECTION_IN_AND_OUT = 1;
957abb7d134c02ac60091108c491dafb00877093170John Hoford
958abb7d134c02ac60091108c491dafb00877093170John Hoford        public enum Style {
959abb7d134c02ac60091108c491dafb00877093170John Hoford            INTERPOLATE, CROSSFADE, WIPE
960abb7d134c02ac60091108c491dafb00877093170John Hoford        }
9619453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
9625c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private final HashSet<String> mSeqMap = new HashSet<String>();
9635c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
9645c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private Interpolator mAnimInterpolator = new AccelerateDecelerateInterpolator();
9655c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private VPath[] mPaths = new VPath[0];
9665c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private long[] mDuration = { DEFAULT_DURATION };
9679453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
9689453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private int[] mThemeAttrs;
969abb7d134c02ac60091108c491dafb00877093170John Hoford        private Style mStyle;
970abb7d134c02ac60091108c491dafb00877093170John Hoford        private int mLimitProperty = 0;
971abb7d134c02ac60091108c491dafb00877093170John Hoford        private long mStartOffset;
972abb7d134c02ac60091108c491dafb00877093170John Hoford        private long mRepeat = 1;
973abb7d134c02ac60091108c491dafb00877093170John Hoford        private long mWipeDirection;
9745c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private int mMode = DIRECTION_FORWARD;
975abb7d134c02ac60091108c491dafb00877093170John Hoford        private int mInterpolatorType;
976abb7d134c02ac60091108c491dafb00877093170John Hoford        private String mId;
977abb7d134c02ac60091108c491dafb00877093170John Hoford
978abb7d134c02ac60091108c491dafb00877093170John Hoford        public VAnimation() {
9799453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            // Empty constructor.
980abb7d134c02ac60091108c491dafb00877093170John Hoford        }
981abb7d134c02ac60091108c491dafb00877093170John Hoford
9829453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void inflate(ArrayList<VGroup> groups, Resources r, AttributeSet attrs, Theme theme)
983abb7d134c02ac60091108c491dafb00877093170John Hoford                throws XmlPullParserException {
984abb7d134c02ac60091108c491dafb00877093170John Hoford            String value;
985abb7d134c02ac60091108c491dafb00877093170John Hoford            String[] sp;
986abb7d134c02ac60091108c491dafb00877093170John Hoford            int name;
987abb7d134c02ac60091108c491dafb00877093170John Hoford
9889453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableAnimation);
9895c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            final int[] themeAttrs = a.extractThemeAttrs();
9905c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mThemeAttrs = themeAttrs;
991abb7d134c02ac60091108c491dafb00877093170John Hoford
992abb7d134c02ac60091108c491dafb00877093170John Hoford            value = a.getString(R.styleable.VectorDrawableAnimation_sequence);
993abb7d134c02ac60091108c491dafb00877093170John Hoford            if (value != null) {
9945c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                sp = value.split(SEPARATOR);
9955c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                final VectorDrawable.VPath[] paths = new VectorDrawable.VPath[sp.length];
996abb7d134c02ac60091108c491dafb00877093170John Hoford
997abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int j = 0; j < sp.length; j++) {
998abb7d134c02ac60091108c491dafb00877093170John Hoford                    mSeqMap.add(sp[j].trim());
999abb7d134c02ac60091108c491dafb00877093170John Hoford                    VectorDrawable.VPath path = groups.get(j).get(sp[j]);
1000abb7d134c02ac60091108c491dafb00877093170John Hoford                    path.mAnimated = true;
1001abb7d134c02ac60091108c491dafb00877093170John Hoford                    paths[j] = path;
1002abb7d134c02ac60091108c491dafb00877093170John Hoford                }
10035c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
1004abb7d134c02ac60091108c491dafb00877093170John Hoford                setPaths(paths);
1005abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1006abb7d134c02ac60091108c491dafb00877093170John Hoford
1007abb7d134c02ac60091108c491dafb00877093170John Hoford            name = R.styleable.VectorDrawableAnimation_durations;
1008abb7d134c02ac60091108c491dafb00877093170John Hoford            value = a.getString(name);
1009abb7d134c02ac60091108c491dafb00877093170John Hoford            if (value != null) {
1010abb7d134c02ac60091108c491dafb00877093170John Hoford                long totalDuration = 0;
10115c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                sp = value.split(SEPARATOR);
10129453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
10139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final long[] dur = new long[sp.length];
1014abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int j = 0; j < dur.length; j++) {
1015abb7d134c02ac60091108c491dafb00877093170John Hoford                    dur[j] = Long.parseLong(sp[j]);
1016abb7d134c02ac60091108c491dafb00877093170John Hoford                    totalDuration +=  dur[j];
1017abb7d134c02ac60091108c491dafb00877093170John Hoford                }
10189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1019abb7d134c02ac60091108c491dafb00877093170John Hoford                if (totalDuration == 0){
10205c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                    throw new XmlPullParserException(a.getPositionDescription()
10215c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                            + " total duration must not be zero");
1022abb7d134c02ac60091108c491dafb00877093170John Hoford                }
10239453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1024abb7d134c02ac60091108c491dafb00877093170John Hoford                setDuration(dur);
1025abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1026abb7d134c02ac60091108c491dafb00877093170John Hoford
10275c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            setLimitProperty(a.getInt(R.styleable.VectorDrawableAnimation_limitTo, 0));
1028abb7d134c02ac60091108c491dafb00877093170John Hoford            setRepeat(a.getInt(R.styleable.VectorDrawableAnimation_repeatCount, 1));
1029abb7d134c02ac60091108c491dafb00877093170John Hoford            setStartOffset(a.getInt(R.styleable.VectorDrawableAnimation_startDelay, 0));
1030abb7d134c02ac60091108c491dafb00877093170John Hoford            setMode(a.getInt(R.styleable.VectorDrawableAnimation_repeatStyle, 0));
1031abb7d134c02ac60091108c491dafb00877093170John Hoford
1032abb7d134c02ac60091108c491dafb00877093170John Hoford            fixMissingParameters();
10339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1034abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
1035abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1036abb7d134c02ac60091108c491dafb00877093170John Hoford
10379453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean canApplyTheme() {
10389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return mThemeAttrs != null;
10399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
10409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
10419453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void applyTheme(Theme t) {
10429453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            // TODO: Apply theme.
10439453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
10449453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
10459453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean doesAdjustPath(VPath path) {
10469453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return mSeqMap.contains(path.getID());
10479453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
10489453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1049abb7d134c02ac60091108c491dafb00877093170John Hoford        public String getId() {
1050abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mId == null) {
1051abb7d134c02ac60091108c491dafb00877093170John Hoford                mId = mPaths[0].getID();
1052abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int i = 1; i < mPaths.length; i++) {
1053abb7d134c02ac60091108c491dafb00877093170John Hoford                    mId += mPaths[i].getID();
1054abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1055abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1056abb7d134c02ac60091108c491dafb00877093170John Hoford            return mId;
1057abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1058abb7d134c02ac60091108c491dafb00877093170John Hoford
1059abb7d134c02ac60091108c491dafb00877093170John Hoford        public String getPathName() {
1060abb7d134c02ac60091108c491dafb00877093170John Hoford            return mPaths[0].getID();
1061abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1062abb7d134c02ac60091108c491dafb00877093170John Hoford
1063abb7d134c02ac60091108c491dafb00877093170John Hoford        public Style getStyle() {
1064abb7d134c02ac60091108c491dafb00877093170John Hoford            return mStyle;
1065abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1066abb7d134c02ac60091108c491dafb00877093170John Hoford
1067abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setStyle(Style style) {
10685c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mStyle = style;
1069abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1070abb7d134c02ac60091108c491dafb00877093170John Hoford
1071abb7d134c02ac60091108c491dafb00877093170John Hoford        public int getLimitProperty() {
1072abb7d134c02ac60091108c491dafb00877093170John Hoford            return mLimitProperty;
1073abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1074abb7d134c02ac60091108c491dafb00877093170John Hoford
1075abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setLimitProperty(int limitProperty) {
10765c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mLimitProperty = limitProperty;
1077abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1078abb7d134c02ac60091108c491dafb00877093170John Hoford
1079abb7d134c02ac60091108c491dafb00877093170John Hoford        public long[] getDuration() {
1080abb7d134c02ac60091108c491dafb00877093170John Hoford            return mDuration;
1081abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1082abb7d134c02ac60091108c491dafb00877093170John Hoford
1083abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setDuration(long[] duration) {
10845c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mDuration = duration;
1085abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1086abb7d134c02ac60091108c491dafb00877093170John Hoford
1087abb7d134c02ac60091108c491dafb00877093170John Hoford        public long getRepeat() {
1088abb7d134c02ac60091108c491dafb00877093170John Hoford            return mRepeat;
1089abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1090abb7d134c02ac60091108c491dafb00877093170John Hoford
1091abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setRepeat(long repeat) {
10925c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mRepeat = repeat;
1093abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1094abb7d134c02ac60091108c491dafb00877093170John Hoford
1095abb7d134c02ac60091108c491dafb00877093170John Hoford        public long getStartOffset() {
1096abb7d134c02ac60091108c491dafb00877093170John Hoford            return mStartOffset;
1097abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1098abb7d134c02ac60091108c491dafb00877093170John Hoford
1099abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setStartOffset(long startOffset) {
11005c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mStartOffset = startOffset;
1101abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1102abb7d134c02ac60091108c491dafb00877093170John Hoford
1103abb7d134c02ac60091108c491dafb00877093170John Hoford        public long getWipeDirection() {
1104abb7d134c02ac60091108c491dafb00877093170John Hoford            return mWipeDirection;
1105abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1106abb7d134c02ac60091108c491dafb00877093170John Hoford
1107abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setWipeDirection(long wipeDirection) {
11085c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mWipeDirection = wipeDirection;
1109abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1110abb7d134c02ac60091108c491dafb00877093170John Hoford
1111abb7d134c02ac60091108c491dafb00877093170John Hoford        public int getMode() {
1112abb7d134c02ac60091108c491dafb00877093170John Hoford            return mMode;
1113abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1114abb7d134c02ac60091108c491dafb00877093170John Hoford
1115abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setMode(int mode) {
11165c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mMode = mode;
1117abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1118abb7d134c02ac60091108c491dafb00877093170John Hoford
1119abb7d134c02ac60091108c491dafb00877093170John Hoford        public int getInterpolator() {
1120abb7d134c02ac60091108c491dafb00877093170John Hoford            return mInterpolatorType;
1121abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1122abb7d134c02ac60091108c491dafb00877093170John Hoford
1123abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setInterpolator(int interpolator) {
11245c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mInterpolatorType = interpolator;
1125abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1126abb7d134c02ac60091108c491dafb00877093170John Hoford
1127abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1128abb7d134c02ac60091108c491dafb00877093170John Hoford         * compute the total time in milliseconds
1129abb7d134c02ac60091108c491dafb00877093170John Hoford         *
1130abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return the total time in milliseconds the animation will take
1131abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1132abb7d134c02ac60091108c491dafb00877093170John Hoford        public long getTotalDuration() {
1133abb7d134c02ac60091108c491dafb00877093170John Hoford            long total = mStartOffset;
1134abb7d134c02ac60091108c491dafb00877093170John Hoford            if (getRepeat() == -1) {
1135abb7d134c02ac60091108c491dafb00877093170John Hoford                return -1;
1136abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1137abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mDuration.length; i++) {
1138abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mRepeat > 1) {
1139abb7d134c02ac60091108c491dafb00877093170John Hoford                    total += mDuration[i] * mRepeat;
1140abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
1141abb7d134c02ac60091108c491dafb00877093170John Hoford                    total += mDuration[i];
1142abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1143abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1144abb7d134c02ac60091108c491dafb00877093170John Hoford            return total;
1145abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1146abb7d134c02ac60091108c491dafb00877093170John Hoford
1147abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setPaths(VPath[] paths) {
11489453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            mPaths = paths;
1149abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1150abb7d134c02ac60091108c491dafb00877093170John Hoford
1151abb7d134c02ac60091108c491dafb00877093170John Hoford        public void addPath(VPath path) {
1152abb7d134c02ac60091108c491dafb00877093170John Hoford            mPaths = Arrays.copyOf(mPaths, mPaths.length + 1);
1153abb7d134c02ac60091108c491dafb00877093170John Hoford            mPaths[mPaths.length - 1] = path;
1154abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1155abb7d134c02ac60091108c491dafb00877093170John Hoford
1156abb7d134c02ac60091108c491dafb00877093170John Hoford        public boolean containsPath(String pathid) {
1157abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mPaths.length; i++) {
1158abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPaths[i].getID().equals(pathid)) {
1159abb7d134c02ac60091108c491dafb00877093170John Hoford                    return true;
1160abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1161abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1162abb7d134c02ac60091108c491dafb00877093170John Hoford            return false;
1163abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1164abb7d134c02ac60091108c491dafb00877093170John Hoford
1165abb7d134c02ac60091108c491dafb00877093170John Hoford        public void interpolate(VPath p1, VPath p2, float time, VPath dest) {
11669453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            VPath.interpolate(time, p1, p2, dest, mLimitProperty);
1167abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1168abb7d134c02ac60091108c491dafb00877093170John Hoford
1169abb7d134c02ac60091108c491dafb00877093170John Hoford        public VPath getPathAtTime(long milliseconds, VPath dest) {
1170abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mPaths.length == 1) {
1171abb7d134c02ac60091108c491dafb00877093170John Hoford                dest.copyFrom(mPaths[0]);
1172abb7d134c02ac60091108c491dafb00877093170John Hoford                return dest;
1173abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1174abb7d134c02ac60091108c491dafb00877093170John Hoford            long point = milliseconds - mStartOffset;
1175abb7d134c02ac60091108c491dafb00877093170John Hoford            if (point < 0) {
1176abb7d134c02ac60091108c491dafb00877093170John Hoford                point = 0;
1177abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1178abb7d134c02ac60091108c491dafb00877093170John Hoford            float time = 0;
1179abb7d134c02ac60091108c491dafb00877093170John Hoford            long sum = mDuration[0];
1180abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 1; i < mDuration.length; i++) {
1181abb7d134c02ac60091108c491dafb00877093170John Hoford                sum += mDuration[i];
1182abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1183abb7d134c02ac60091108c491dafb00877093170John Hoford
1184abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mRepeat > 1) {
1185abb7d134c02ac60091108c491dafb00877093170John Hoford                time = point / (float) (sum * mRepeat);
1186abb7d134c02ac60091108c491dafb00877093170John Hoford                time = mAnimInterpolator.getInterpolation(time);
1187abb7d134c02ac60091108c491dafb00877093170John Hoford
1188abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mMode == DIRECTION_IN_AND_OUT) {
1189abb7d134c02ac60091108c491dafb00877093170John Hoford                    point = ((long) (time * sum * 2 * mRepeat)) % (sum * 2);
1190abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (point > sum) {
1191abb7d134c02ac60091108c491dafb00877093170John Hoford                        point = sum * 2 - point;
1192abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1193abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
1194abb7d134c02ac60091108c491dafb00877093170John Hoford                    point = ((long) (time * sum * mRepeat)) % sum;
1195abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1196abb7d134c02ac60091108c491dafb00877093170John Hoford            } else if (mRepeat == 1) {
1197abb7d134c02ac60091108c491dafb00877093170John Hoford                time = point / (float) (sum * mRepeat);
1198abb7d134c02ac60091108c491dafb00877093170John Hoford                time = mAnimInterpolator.getInterpolation(time);
1199abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mMode == DIRECTION_IN_AND_OUT) {
1200abb7d134c02ac60091108c491dafb00877093170John Hoford                    point = ((long) (time * sum * 2 * mRepeat));
1201abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (point > sum) {
1202abb7d134c02ac60091108c491dafb00877093170John Hoford                        point = sum * 2 - point;
1203abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1204abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
1205abb7d134c02ac60091108c491dafb00877093170John Hoford                    point = Math.min(((long) (time * sum * mRepeat)), sum);
1206abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1207abb7d134c02ac60091108c491dafb00877093170John Hoford
1208abb7d134c02ac60091108c491dafb00877093170John Hoford            } else { // repeat = -1
1209abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mMode == DIRECTION_IN_AND_OUT) {
1210abb7d134c02ac60091108c491dafb00877093170John Hoford                    point = point % (sum * 2);
1211abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (point > sum) {
1212abb7d134c02ac60091108c491dafb00877093170John Hoford                        point = sum * 2 - point;
1213abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1214abb7d134c02ac60091108c491dafb00877093170John Hoford                    time = point / (float) sum;
1215abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
1216abb7d134c02ac60091108c491dafb00877093170John Hoford                    point = point % sum;
1217abb7d134c02ac60091108c491dafb00877093170John Hoford                    time = point / (float) sum;
1218abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1219abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1220abb7d134c02ac60091108c491dafb00877093170John Hoford
1221abb7d134c02ac60091108c491dafb00877093170John Hoford            int transition = 0;
1222abb7d134c02ac60091108c491dafb00877093170John Hoford            while (point > mDuration[transition]) {
1223abb7d134c02ac60091108c491dafb00877093170John Hoford                point -= mDuration[transition++];
1224abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1225abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mPaths.length > (transition + 1)) {
1226abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPaths[transition].getID() != dest.getID()) {
1227abb7d134c02ac60091108c491dafb00877093170John Hoford                    dest.copyFrom(mPaths[transition]);
1228abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1229abb7d134c02ac60091108c491dafb00877093170John Hoford                interpolate(mPaths[transition], mPaths[transition + 1],
1230abb7d134c02ac60091108c491dafb00877093170John Hoford                        point / (float) mDuration[transition], dest);
1231abb7d134c02ac60091108c491dafb00877093170John Hoford            } else {
1232abb7d134c02ac60091108c491dafb00877093170John Hoford                interpolate(mPaths[transition], mPaths[transition], 0, dest);
1233abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1234abb7d134c02ac60091108c491dafb00877093170John Hoford            return dest;
1235abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1236abb7d134c02ac60091108c491dafb00877093170John Hoford
1237abb7d134c02ac60091108c491dafb00877093170John Hoford        void fixMissingParameters() {
1238abb7d134c02ac60091108c491dafb00877093170John Hoford            // fix missing points
1239abb7d134c02ac60091108c491dafb00877093170John Hoford            float rotation = Float.NaN;
1240abb7d134c02ac60091108c491dafb00877093170John Hoford            float rotationY = Float.NaN;
1241abb7d134c02ac60091108c491dafb00877093170John Hoford            float rotationX = Float.NaN;
1242abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mPaths.length; i++) {
1243abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPaths[i].mPivotX > 0) {
1244abb7d134c02ac60091108c491dafb00877093170John Hoford                    rotationX = mPaths[i].mPivotX;
1245abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1246abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPaths[i].mPivotY > 0) {
1247abb7d134c02ac60091108c491dafb00877093170John Hoford                    rotationY = mPaths[i].mPivotY;
1248abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1249abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPaths[i].mRotate > 0) {
1250abb7d134c02ac60091108c491dafb00877093170John Hoford                    rotation = mPaths[i].mRotate;
1251abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1252abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1253abb7d134c02ac60091108c491dafb00877093170John Hoford            if (rotation > 0) {
1254abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int i = 0; i < mPaths.length; i++) {
1255abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (mPaths[i].mPivotX == 0) {
1256abb7d134c02ac60091108c491dafb00877093170John Hoford                        mPaths[i].mPivotX = rotationX;
1257abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1258abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (mPaths[i].mPivotY == 0) {
1259abb7d134c02ac60091108c491dafb00877093170John Hoford                        mPaths[i].mPivotY = rotationY;
1260abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1261abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1262abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1263abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1264abb7d134c02ac60091108c491dafb00877093170John Hoford    }
1265abb7d134c02ac60091108c491dafb00877093170John Hoford
1266abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VGroup {
12679453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private final HashMap<String, VPath> mVGPathMap = new HashMap<String, VPath>();
12689453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private final ArrayList<VPath> mVGList = new ArrayList<VPath>();
1269abb7d134c02ac60091108c491dafb00877093170John Hoford
1270abb7d134c02ac60091108c491dafb00877093170John Hoford        public void add(VPath path) {
1271abb7d134c02ac60091108c491dafb00877093170John Hoford            String id = path.getID();
1272abb7d134c02ac60091108c491dafb00877093170John Hoford            mVGPathMap.put(id, path);
1273abb7d134c02ac60091108c491dafb00877093170John Hoford            mVGList.add(path);
1274abb7d134c02ac60091108c491dafb00877093170John Hoford         }
1275abb7d134c02ac60091108c491dafb00877093170John Hoford
1276abb7d134c02ac60091108c491dafb00877093170John Hoford        public VPath get(String name) {
1277abb7d134c02ac60091108c491dafb00877093170John Hoford            return mVGPathMap.get(name);
1278abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1279abb7d134c02ac60091108c491dafb00877093170John Hoford
1280abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1281abb7d134c02ac60091108c491dafb00877093170John Hoford         * Must return in order of adding
1282abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return ordered list of paths
1283abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1284abb7d134c02ac60091108c491dafb00877093170John Hoford        public Collection<VPath> getPaths() {
1285abb7d134c02ac60091108c491dafb00877093170John Hoford            return mVGList;
1286abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1287abb7d134c02ac60091108c491dafb00877093170John Hoford
1288abb7d134c02ac60091108c491dafb00877093170John Hoford        public int size() {
1289abb7d134c02ac60091108c491dafb00877093170John Hoford            return mVGPathMap.size();
1290abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1291abb7d134c02ac60091108c491dafb00877093170John Hoford    }
1292abb7d134c02ac60091108c491dafb00877093170John Hoford
1293abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VPath {
1294abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int LIMIT_ALL = 0;
1295abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int LIMIT_PATH = 1;
1296abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int LIMIT_ROTATE = 2;
1297abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int LIMIT_TRIM_PATH_START = 3;
1298abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int LIMIT_TRIM_PATH_OFFSET = 5;
1299abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int LIMIT_TRIM_PATH_END = 4;
13009453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1301abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int STATE_UNDEFINED=0;
1302abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int STATE_TRUE=1;
1303abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int STATE_FALSE=2;
13049453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1305abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int MAX_STATES = 10;
13069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
13079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private int[] mThemeAttrs;
13089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1309abb7d134c02ac60091108c491dafb00877093170John Hoford        int mStrokeColor = 0;
1310abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeWidth = 0;
1311abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeOpacity = Float.NaN;
13129453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1313abb7d134c02ac60091108c491dafb00877093170John Hoford        int mFillColor = 0;
1314abb7d134c02ac60091108c491dafb00877093170John Hoford        int mFillRule;
1315abb7d134c02ac60091108c491dafb00877093170John Hoford        float mFillOpacity = Float.NaN;
13169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1317abb7d134c02ac60091108c491dafb00877093170John Hoford        float mRotate = 0;
1318abb7d134c02ac60091108c491dafb00877093170John Hoford        float mPivotX = 0;
1319abb7d134c02ac60091108c491dafb00877093170John Hoford        float mPivotY = 0;
13209453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1321abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathStart = 0;
1322abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathEnd = 1;
1323abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathOffset = 0;
13249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1325abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean mAnimated = false;
1326abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean mClip = false;
13277f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        Paint.Cap mStrokeLineCap = null;
13287f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        Paint.Join mStrokeLineJoin = null;
1329abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeMiterlimit = 4;
13309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
13319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private VNode[] mNode = null;
13329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private String mId;
1333abb7d134c02ac60091108c491dafb00877093170John Hoford        private int[] mCheckState = new int[MAX_STATES];
1334abb7d134c02ac60091108c491dafb00877093170John Hoford        private boolean[] mCheckValue = new boolean[MAX_STATES];
1335abb7d134c02ac60091108c491dafb00877093170John Hoford        private int mNumberOfStates = 0;
1336abb7d134c02ac60091108c491dafb00877093170John Hoford        private int mNumberOfTrue = 0;
1337abb7d134c02ac60091108c491dafb00877093170John Hoford
13389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public VPath() {
13399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            // Empty constructor.
13409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
13419453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
13429453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public VPath(VPath p) {
13439453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            copyFrom(p);
13449453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
13459453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1346abb7d134c02ac60091108c491dafb00877093170John Hoford        public void addStateFilter(int state, boolean condition) {
1347abb7d134c02ac60091108c491dafb00877093170John Hoford            int k = 0;
1348abb7d134c02ac60091108c491dafb00877093170John Hoford            while (k < mNumberOfStates) {
1349abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mCheckState[mNumberOfStates] == state)
1350abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1351abb7d134c02ac60091108c491dafb00877093170John Hoford                k++;
1352abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1353abb7d134c02ac60091108c491dafb00877093170John Hoford            mCheckState[k] = state;
1354abb7d134c02ac60091108c491dafb00877093170John Hoford            mCheckValue[k] = condition;
1355abb7d134c02ac60091108c491dafb00877093170John Hoford            if (k==mNumberOfStates){
1356abb7d134c02ac60091108c491dafb00877093170John Hoford                mNumberOfStates++;
1357abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1358abb7d134c02ac60091108c491dafb00877093170John Hoford            if (condition) {
1359abb7d134c02ac60091108c491dafb00877093170John Hoford                mNumberOfTrue++;
1360abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1361abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1362abb7d134c02ac60091108c491dafb00877093170John Hoford
13639453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private int getState(int state){
1364abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mNumberOfStates; i++) {
1365abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mCheckState[mNumberOfStates] == state){
1366abb7d134c02ac60091108c491dafb00877093170John Hoford                    return (mCheckValue[i])?STATE_TRUE:STATE_FALSE;
1367abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1368abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1369abb7d134c02ac60091108c491dafb00877093170John Hoford            return STATE_UNDEFINED;
1370abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1371abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1372abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return the name of the path
1373abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1374abb7d134c02ac60091108c491dafb00877093170John Hoford        public String getName() {
1375abb7d134c02ac60091108c491dafb00877093170John Hoford            return mId;
1376abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1377abb7d134c02ac60091108c491dafb00877093170John Hoford
1378abb7d134c02ac60091108c491dafb00877093170John Hoford        public void toPath(Path path) {
1379abb7d134c02ac60091108c491dafb00877093170John Hoford            path.reset();
1380abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mNode != null) {
1381abb7d134c02ac60091108c491dafb00877093170John Hoford                VNode.createPath(mNode, path);
1382abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1383abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1384abb7d134c02ac60091108c491dafb00877093170John Hoford
13857f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        public String getID() {
1386abb7d134c02ac60091108c491dafb00877093170John Hoford            return mId;
1387abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1388abb7d134c02ac60091108c491dafb00877093170John Hoford
13897f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) {
13907f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            switch (id) {
13917f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_BUTT:
13927f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.BUTT;
13937f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_ROUND:
13947f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.ROUND;
13957f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_SQUARE:
13967f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.SQUARE;
13977f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                default:
13987f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return defValue;
13997f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14007f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        }
14017f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
14027f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        private Paint.Join getStrokeLineJoin(int id, Paint.Join defValue) {
14037f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            switch (id) {
14047f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_MITER:
14057f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.MITER;
14067f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_ROUND:
14077f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.ROUND;
14087f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_BEVEL:
14097f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.BEVEL;
14107f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                default:
14117f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return defValue;
14127f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14137f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        }
14147f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
14159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void inflate(Resources r, AttributeSet attrs, Theme theme) {
14169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawablePath);
14179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int[] themeAttrs = a.extractThemeAttrs();
14189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            mThemeAttrs = themeAttrs;
14199453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14207f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            // NOTE: The set of attributes loaded here MUST match the
14217f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            // set of attributes loaded in applyTheme.
14227f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_clipToPath] == 0) {
14237f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
14247f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14257f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
14267f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_name] == 0) {
14277f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mId = a.getString(R.styleable.VectorDrawablePath_name);
14287f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14297f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
14307f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pathData] == 0) {
14317f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData));
14327f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
1433abb7d134c02ac60091108c491dafb00877093170John Hoford
14349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fill] == 0) {
14357f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor);
14369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
14379453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14387f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fillOpacity] == 0) {
14397f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity);
1440abb7d134c02ac60091108c491dafb00877093170John Hoford            }
14419453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14427f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_rotation] == 0) {
14437f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mRotate = a.getFloat(R.styleable.VectorDrawablePath_rotation, mRotate);
14447f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14459453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14467f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pivotX] == 0) {
14477f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mPivotX = a.getFloat(R.styleable.VectorDrawablePath_pivotX, mPivotX);
1448abb7d134c02ac60091108c491dafb00877093170John Hoford            }
14499453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14507f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pivotY] == 0) {
14517f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mPivotY = a.getFloat(R.styleable.VectorDrawablePath_pivotY, mPivotY);
14527f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14537f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
14547f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
14557f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeLineCap] == 0) {
14567f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeLineCap = getStrokeLineCap(
14577f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        a.getInt(R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
14587f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14597f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
14607f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
14617f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeLineJoin] == 0) {
14627f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeLineJoin = getStrokeLineJoin(
14637f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        a.getInt(R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
1464abb7d134c02ac60091108c491dafb00877093170John Hoford            }
14659453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14667f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
14677f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeMiterLimit] == 0) {
14687f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeMiterlimit = a.getFloat(
14697f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
14707f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14719453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14729453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_stroke] == 0) {
14739453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor);
1474abb7d134c02ac60091108c491dafb00877093170John Hoford            }
14759453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14769453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null
14779453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeOpacity] == 0) {
14789453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeOpacity = a.getFloat(
14797f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity);
14809453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
14819453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14827f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_strokeWidth] == 0) {
14837f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth);
14847f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14857f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
14867f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_trimPathEnd] == 0) {
14877f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd);
14887f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14899453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14907f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
14917f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_trimPathOffset] == 0) {
14927f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathOffset = a.getFloat(
14937f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
14947f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14957f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
14967f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
14977f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_trimPathStart] == 0) {
14987f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathStart = a.getFloat(
14997f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
15007f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
15017f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
15027f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            // TODO: Consider replacing this with existing state attributes.
15039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int[] states = {
15049453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    R.styleable.VectorDrawablePath_state_activated,
1505abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_checkable,
1506abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_checked,
1507abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_enabled,
1508abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_focused,
1509abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_hovered,
1510abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_pressed,
1511abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_selected,
15129453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    R.styleable.VectorDrawablePath_state_window_focused
15139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            };
15149453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int N = states.length;
15169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            for (int i = 0; i < N; i++) {
15179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final int state = states[i];
1518abb7d134c02ac60091108c491dafb00877093170John Hoford                if (a.hasValue(state)) {
1519abb7d134c02ac60091108c491dafb00877093170John Hoford                    addStateFilter(state, a.getBoolean(state, false));
1520abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1521abb7d134c02ac60091108c491dafb00877093170John Hoford            }
15229453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15239453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            updateColorAlphas();
15249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1525abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
1526abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1527abb7d134c02ac60091108c491dafb00877093170John Hoford
15289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean canApplyTheme() {
15299453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return mThemeAttrs != null;
15309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
15319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void applyTheme(Theme t) {
15339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (mThemeAttrs == null) {
15349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                return;
15359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
15369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15379453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final TypedArray a = t.resolveAttributes(
15389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    mThemeAttrs, R.styleable.VectorDrawablePath, 0, 0);
15399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15407f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
15419453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15427f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (a.hasValue(R.styleable.VectorDrawablePath_name)) {
15437f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mId = a.getString(R.styleable.VectorDrawablePath_name);
15449453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
15459453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15467f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (a.hasValue(R.styleable.VectorDrawablePath_pathData)) {
15477f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData));
15489453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
15499453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15507f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor);
15517f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity);
15527f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
15537f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mRotate = a.getFloat(R.styleable.VectorDrawablePath_rotation, mRotate);
15547f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mPivotX = a.getFloat(R.styleable.VectorDrawablePath_pivotX, mPivotX);
15557f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mPivotY = a.getFloat(R.styleable.VectorDrawablePath_pivotY, mPivotY);
15567f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
15577f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineCap = getStrokeLineCap(a.getInt(
15587f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
15597f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineJoin = getStrokeLineJoin(a.getInt(
15607f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
15617f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeMiterlimit = a.getFloat(
15627f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
15637f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor);
15647f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeOpacity = a.getFloat(
15657f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity);
15667f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth);
15677f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
15687f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd);
15697f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathOffset = a.getFloat(
15707f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
15717f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathStart = a.getFloat(
15727f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
15739453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15749453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            updateColorAlphas();
15759453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
15769453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15779453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private void updateColorAlphas() {
15789453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (!Float.isNaN(mFillOpacity)) {
15799453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mFillColor &= 0x00FFFFFF;
15809453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mFillColor |= ((int) (0xFF * mFillOpacity)) << 24;
15819453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
15829453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15839453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (!Float.isNaN(mStrokeOpacity)) {
15849453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor &= 0x00FFFFFF;
15859453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor |= ((int) (0xFF * mStrokeOpacity)) << 24;
15869453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
15879453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
15889453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1589abb7d134c02ac60091108c491dafb00877093170John Hoford        private static int nextStart(String s, int end) {
1590abb7d134c02ac60091108c491dafb00877093170John Hoford            char c;
1591abb7d134c02ac60091108c491dafb00877093170John Hoford
1592abb7d134c02ac60091108c491dafb00877093170John Hoford            while (end < s.length()) {
1593abb7d134c02ac60091108c491dafb00877093170John Hoford                c = s.charAt(end);
1594abb7d134c02ac60091108c491dafb00877093170John Hoford                if (((c - 'A') * (c - 'Z') <= 0) || (((c - 'a') * (c - 'z') <= 0))) {
1595abb7d134c02ac60091108c491dafb00877093170John Hoford                    return end;
1596abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1597abb7d134c02ac60091108c491dafb00877093170John Hoford                end++;
1598abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1599abb7d134c02ac60091108c491dafb00877093170John Hoford            return end;
1600abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1601abb7d134c02ac60091108c491dafb00877093170John Hoford
1602abb7d134c02ac60091108c491dafb00877093170John Hoford        private void addNode(ArrayList<VectorDrawable.VNode> list, char cmd, float[] val) {
1603abb7d134c02ac60091108c491dafb00877093170John Hoford            list.add(new VectorDrawable.VNode(cmd, val));
1604abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1605abb7d134c02ac60091108c491dafb00877093170John Hoford
1606abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1607abb7d134c02ac60091108c491dafb00877093170John Hoford         * parse the floats in the string
1608abb7d134c02ac60091108c491dafb00877093170John Hoford         * this is an optimized version of
1609abb7d134c02ac60091108c491dafb00877093170John Hoford         * parseFloat(s.split(",|\\s"));
1610abb7d134c02ac60091108c491dafb00877093170John Hoford         *
1611abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param s the string containing a command and list of floats
1612abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return array of floats
1613abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1614abb7d134c02ac60091108c491dafb00877093170John Hoford        private static float[] getFloats(String s) {
1615abb7d134c02ac60091108c491dafb00877093170John Hoford            if (s.charAt(0) == 'z' | s.charAt(0) == 'Z') {
1616abb7d134c02ac60091108c491dafb00877093170John Hoford                return new float[0];
1617abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1618abb7d134c02ac60091108c491dafb00877093170John Hoford            try {
1619abb7d134c02ac60091108c491dafb00877093170John Hoford                float[] tmp = new float[s.length()];
1620abb7d134c02ac60091108c491dafb00877093170John Hoford                int count = 0;
1621abb7d134c02ac60091108c491dafb00877093170John Hoford                int pos = 1, end;
1622abb7d134c02ac60091108c491dafb00877093170John Hoford                while ((end = extract(s, pos)) >= 0) {
1623abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (pos < end) {
1624abb7d134c02ac60091108c491dafb00877093170John Hoford                        tmp[count++] = Float.parseFloat(s.substring(pos, end));
1625abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1626abb7d134c02ac60091108c491dafb00877093170John Hoford                    pos = end + 1;
1627abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1628abb7d134c02ac60091108c491dafb00877093170John Hoford                // handle the final float if there is one
1629abb7d134c02ac60091108c491dafb00877093170John Hoford                if (pos < s.length()) {
1630abb7d134c02ac60091108c491dafb00877093170John Hoford                    tmp[count++] = Float.parseFloat(s.substring(pos, s.length()));
1631abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1632abb7d134c02ac60091108c491dafb00877093170John Hoford                return Arrays.copyOf(tmp, count);
1633abb7d134c02ac60091108c491dafb00877093170John Hoford            } catch (NumberFormatException e){
1634abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.e(LOGTAG,"error in parsing \""+s+"\"");
1635abb7d134c02ac60091108c491dafb00877093170John Hoford                throw e;
1636abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1637abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1638abb7d134c02ac60091108c491dafb00877093170John Hoford
1639abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1640abb7d134c02ac60091108c491dafb00877093170John Hoford         * calculate the position of the next comma or space
1641abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param s the string to search
1642abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param start the position to start searching
1643abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return the position of the next comma or space or -1 if none found
1644abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1645abb7d134c02ac60091108c491dafb00877093170John Hoford        private static int extract(String s, int start) {
1646abb7d134c02ac60091108c491dafb00877093170John Hoford            int space = s.indexOf(' ', start);
1647abb7d134c02ac60091108c491dafb00877093170John Hoford            int comma = s.indexOf(',', start);
1648abb7d134c02ac60091108c491dafb00877093170John Hoford            if (space == -1) {
1649abb7d134c02ac60091108c491dafb00877093170John Hoford                return comma;
1650abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1651abb7d134c02ac60091108c491dafb00877093170John Hoford            if (comma == -1) {
1652abb7d134c02ac60091108c491dafb00877093170John Hoford                return space;
1653abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1654abb7d134c02ac60091108c491dafb00877093170John Hoford            return (comma > space) ? space : comma;
1655abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1656abb7d134c02ac60091108c491dafb00877093170John Hoford
1657abb7d134c02ac60091108c491dafb00877093170John Hoford        private VectorDrawable.VNode[] parsePath(String value) {
1658abb7d134c02ac60091108c491dafb00877093170John Hoford            int start = 0;
1659abb7d134c02ac60091108c491dafb00877093170John Hoford            int end = 1;
1660abb7d134c02ac60091108c491dafb00877093170John Hoford
1661abb7d134c02ac60091108c491dafb00877093170John Hoford            ArrayList<VectorDrawable.VNode> list = new ArrayList<VectorDrawable.VNode>();
1662abb7d134c02ac60091108c491dafb00877093170John Hoford            while (end < value.length()) {
1663abb7d134c02ac60091108c491dafb00877093170John Hoford                end = nextStart(value, end);
1664abb7d134c02ac60091108c491dafb00877093170John Hoford                String s = value.substring(start, end);
1665abb7d134c02ac60091108c491dafb00877093170John Hoford                float[] val = getFloats(s);
1666abb7d134c02ac60091108c491dafb00877093170John Hoford                addNode(list, s.charAt(0), val);
1667abb7d134c02ac60091108c491dafb00877093170John Hoford
1668abb7d134c02ac60091108c491dafb00877093170John Hoford                start = end;
1669abb7d134c02ac60091108c491dafb00877093170John Hoford                end++;
1670abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1671abb7d134c02ac60091108c491dafb00877093170John Hoford            if ((end - start) == 1 && start < value.length()) {
1672abb7d134c02ac60091108c491dafb00877093170John Hoford
1673abb7d134c02ac60091108c491dafb00877093170John Hoford                addNode(list, value.charAt(start), new float[0]);
1674abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1675abb7d134c02ac60091108c491dafb00877093170John Hoford            return list.toArray(new VectorDrawable.VNode[list.size()]);
1676abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1677abb7d134c02ac60091108c491dafb00877093170John Hoford
1678abb7d134c02ac60091108c491dafb00877093170John Hoford        public void copyFrom(VPath p1) {
1679abb7d134c02ac60091108c491dafb00877093170John Hoford            mNode = new VNode[p1.mNode.length];
1680abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mNode.length; i++) {
1681abb7d134c02ac60091108c491dafb00877093170John Hoford                mNode[i] = new VNode(p1.mNode[i]);
1682abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1683abb7d134c02ac60091108c491dafb00877093170John Hoford            mId = p1.mId;
1684abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokeColor = p1.mStrokeColor;
1685abb7d134c02ac60091108c491dafb00877093170John Hoford            mFillColor = p1.mFillColor;
1686abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokeWidth = p1.mStrokeWidth;
1687abb7d134c02ac60091108c491dafb00877093170John Hoford            mRotate = p1.mRotate;
1688abb7d134c02ac60091108c491dafb00877093170John Hoford            mPivotX = p1.mPivotX;
1689abb7d134c02ac60091108c491dafb00877093170John Hoford            mPivotY = p1.mPivotY;
1690abb7d134c02ac60091108c491dafb00877093170John Hoford            mAnimated = p1.mAnimated;
1691abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrimPathStart = p1.mTrimPathStart;
1692abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrimPathEnd = p1.mTrimPathEnd;
1693abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrimPathOffset = p1.mTrimPathOffset;
16947f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineCap = p1.mStrokeLineCap;
16957f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineJoin = p1.mStrokeLineJoin;
1696abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokeMiterlimit = p1.mStrokeMiterlimit;
1697abb7d134c02ac60091108c491dafb00877093170John Hoford            mNumberOfStates = p1.mNumberOfStates;
1698abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mNumberOfStates; i++) {
1699abb7d134c02ac60091108c491dafb00877093170John Hoford                mCheckState[i] = p1.mCheckState[i];
1700abb7d134c02ac60091108c491dafb00877093170John Hoford                mCheckValue[i] = p1.mCheckValue[i];
1701abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1702abb7d134c02ac60091108c491dafb00877093170John Hoford
1703abb7d134c02ac60091108c491dafb00877093170John Hoford            mFillRule = p1.mFillRule;
1704abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1705abb7d134c02ac60091108c491dafb00877093170John Hoford
1706abb7d134c02ac60091108c491dafb00877093170John Hoford        public static VPath interpolate(float t, VPath p1, VPath p2, VPath returnPath, int limit) {
1707abb7d134c02ac60091108c491dafb00877093170John Hoford            if (limit == LIMIT_ALL || limit == LIMIT_PATH) {
1708abb7d134c02ac60091108c491dafb00877093170John Hoford                if (returnPath.mNode == null || returnPath.mNode.length != p1.mNode.length) {
1709abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mNode = new VNode[p1.mNode.length];
1710abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1711abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int i = 0; i < returnPath.mNode.length; i++) {
1712abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (returnPath.mNode[i] == null) {
1713abb7d134c02ac60091108c491dafb00877093170John Hoford                        returnPath.mNode[i] = new VNode(p1.mNode[i], p2.mNode[i], t);
1714abb7d134c02ac60091108c491dafb00877093170John Hoford                    } else {
1715abb7d134c02ac60091108c491dafb00877093170John Hoford                        returnPath.mNode[i].interpolate(p1.mNode[i], p2.mNode[i], t);
1716abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1717abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1718abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1719abb7d134c02ac60091108c491dafb00877093170John Hoford            float t1 = 1 - t;
1720abb7d134c02ac60091108c491dafb00877093170John Hoford            switch (limit) {
1721abb7d134c02ac60091108c491dafb00877093170John Hoford                case LIMIT_ALL:
1722abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mRotate = t1 * p1.mRotate + t * p2.mRotate;
1723abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mPivotX = t1 * p1.mPivotX + t * p2.mPivotX;
1724abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mPivotY = t1 * p1.mPivotY + t * p2.mPivotY;
1725abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mClip = p1.mClip | p2.mClip;
1726abb7d134c02ac60091108c491dafb00877093170John Hoford
1727abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mTrimPathStart = t1 * p1.mTrimPathStart + t * p2.mTrimPathStart;
1728abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mTrimPathEnd = t1 * p1.mTrimPathEnd + t * p2.mTrimPathEnd;
1729abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mTrimPathOffset = t1 * p1.mTrimPathOffset + t * p2.mTrimPathOffset;
1730abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mStrokeMiterlimit =
1731abb7d134c02ac60091108c491dafb00877093170John Hoford                            t1 * p1.mStrokeMiterlimit + t * p2.mStrokeMiterlimit;
17327f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    returnPath.mStrokeLineCap = p1.mStrokeLineCap;
17337f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    if (returnPath.mStrokeLineCap == null) {
17347f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        returnPath.mStrokeLineCap = p2.mStrokeLineCap;
1735abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
17367f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    returnPath.mStrokeLineJoin = p1.mStrokeLineJoin;
17377f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    if (returnPath.mStrokeLineJoin == null) {
17387f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        returnPath.mStrokeLineJoin = p2.mStrokeLineJoin;
1739abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1740abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mFillRule = p1.mFillRule;
1741abb7d134c02ac60091108c491dafb00877093170John Hoford
1742abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mStrokeColor = rgbInterpolate(t, p1.mStrokeColor, p2.mStrokeColor);
1743abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mFillColor = rgbInterpolate(t, p1.mFillColor, p2.mFillColor);
1744abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mStrokeWidth = t1 * p1.mStrokeWidth + t * p2.mStrokeWidth;
1745abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mNumberOfStates = p1.mNumberOfStates;
1746abb7d134c02ac60091108c491dafb00877093170John Hoford                    for (int i = 0; i < returnPath.mNumberOfStates; i++) {
1747abb7d134c02ac60091108c491dafb00877093170John Hoford                        returnPath.mCheckState[i] = p1.mCheckState[i];
1748abb7d134c02ac60091108c491dafb00877093170John Hoford                        returnPath.mCheckValue[i] = p1.mCheckValue[i];
1749abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1750abb7d134c02ac60091108c491dafb00877093170John Hoford                    for (int i = 0; i < p2.mNumberOfStates; i++) {
1751abb7d134c02ac60091108c491dafb00877093170John Hoford                        returnPath.addStateFilter(p2.mCheckState[i], p2.mCheckValue[i]);
1752abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1753abb7d134c02ac60091108c491dafb00877093170John Hoford
1754abb7d134c02ac60091108c491dafb00877093170John Hoford                    int count = 0;
1755abb7d134c02ac60091108c491dafb00877093170John Hoford                    for (int i = 0; i < returnPath.mNumberOfStates; i++) {
1756abb7d134c02ac60091108c491dafb00877093170John Hoford                        if (returnPath.mCheckValue[i]) {
1757abb7d134c02ac60091108c491dafb00877093170John Hoford                            count++;
1758abb7d134c02ac60091108c491dafb00877093170John Hoford                        }
1759abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1760abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mNumberOfTrue = count;
1761abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1762abb7d134c02ac60091108c491dafb00877093170John Hoford                case LIMIT_ROTATE:
1763abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mRotate = t1 * p1.mRotate + t * p2.mRotate;
1764abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1765abb7d134c02ac60091108c491dafb00877093170John Hoford                case LIMIT_TRIM_PATH_END:
1766abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mTrimPathEnd = t1 * p1.mTrimPathEnd + t * p2.mTrimPathEnd;
1767abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1768abb7d134c02ac60091108c491dafb00877093170John Hoford                case LIMIT_TRIM_PATH_OFFSET:
1769abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mTrimPathOffset = t1 * p1.mTrimPathOffset + t * p2.mTrimPathOffset;
1770abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1771abb7d134c02ac60091108c491dafb00877093170John Hoford                case LIMIT_TRIM_PATH_START:
1772abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mTrimPathStart = t1 * p1.mTrimPathStart + t * p2.mTrimPathStart;
1773abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1774abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1775abb7d134c02ac60091108c491dafb00877093170John Hoford            return returnPath;
1776abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1777abb7d134c02ac60091108c491dafb00877093170John Hoford
1778abb7d134c02ac60091108c491dafb00877093170John Hoford        private static int rgbInterpolate(float t, int color1, int color2) {
1779abb7d134c02ac60091108c491dafb00877093170John Hoford            int ret;
1780abb7d134c02ac60091108c491dafb00877093170John Hoford            if (color1 == color2) {
1781abb7d134c02ac60091108c491dafb00877093170John Hoford                return color2;
1782abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1783abb7d134c02ac60091108c491dafb00877093170John Hoford            if (color1 == 0) {
1784abb7d134c02ac60091108c491dafb00877093170John Hoford                return color2;
1785abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1786abb7d134c02ac60091108c491dafb00877093170John Hoford            if (color2 == 0) {
1787abb7d134c02ac60091108c491dafb00877093170John Hoford                return color1;
1788abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1789abb7d134c02ac60091108c491dafb00877093170John Hoford
1790abb7d134c02ac60091108c491dafb00877093170John Hoford            float t1 = 1 - t;
1791abb7d134c02ac60091108c491dafb00877093170John Hoford            ret = 0xFF & (((int) ((color1 & 0xFF) * t1 + (color2 & 0xFF) * t)));
1792abb7d134c02ac60091108c491dafb00877093170John Hoford            color1 >>= 8;
1793abb7d134c02ac60091108c491dafb00877093170John Hoford                    color2 >>= 8;
1794abb7d134c02ac60091108c491dafb00877093170John Hoford
1795abb7d134c02ac60091108c491dafb00877093170John Hoford                    ret |= 0xFF00 & (((int) ((color1 & 0xFF) * t1 + (color2 & 0xFF) * t)) << 8);
1796abb7d134c02ac60091108c491dafb00877093170John Hoford                    color1 >>= 8;
1797abb7d134c02ac60091108c491dafb00877093170John Hoford                    color2 >>= 8;
1798abb7d134c02ac60091108c491dafb00877093170John Hoford            ret |= 0xFF0000 & (((int) ((color1 & 0xFF) * t1 + (color2 & 0xFF) * t)) << 16);
1799abb7d134c02ac60091108c491dafb00877093170John Hoford            color1 >>= 8;
1800abb7d134c02ac60091108c491dafb00877093170John Hoford            color2 >>= 8;
1801abb7d134c02ac60091108c491dafb00877093170John Hoford            ret |= 0xFF000000 & (((int) ((color1 & 0xFF) * t1 + (color2 & 0xFF) * t)) << 24);
1802abb7d134c02ac60091108c491dafb00877093170John Hoford
1803abb7d134c02ac60091108c491dafb00877093170John Hoford            return ret;
1804abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1805abb7d134c02ac60091108c491dafb00877093170John Hoford
1806abb7d134c02ac60091108c491dafb00877093170John Hoford        public boolean isVisible(int[] state) {
1807abb7d134c02ac60091108c491dafb00877093170John Hoford            int match = 0;
1808abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < state.length; i++) {
1809abb7d134c02ac60091108c491dafb00877093170John Hoford                int v = getState(state[i]);
1810abb7d134c02ac60091108c491dafb00877093170John Hoford                if (v != STATE_UNDEFINED) {
1811abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (v==STATE_TRUE) {
1812abb7d134c02ac60091108c491dafb00877093170John Hoford                        match++;
1813abb7d134c02ac60091108c491dafb00877093170John Hoford                    } else {
1814abb7d134c02ac60091108c491dafb00877093170John Hoford                        return false;
1815abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1816abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1817abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1818abb7d134c02ac60091108c491dafb00877093170John Hoford            return match == mNumberOfTrue;
1819abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1820abb7d134c02ac60091108c491dafb00877093170John Hoford    }
1821abb7d134c02ac60091108c491dafb00877093170John Hoford
1822abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VNode {
18235c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private char mType;
18245c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private float[] mParams;
18259453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1826abb7d134c02ac60091108c491dafb00877093170John Hoford        public VNode(char type, float[] params) {
18275c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mType = type;
18285c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mParams = params;
1829abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1830abb7d134c02ac60091108c491dafb00877093170John Hoford
1831abb7d134c02ac60091108c491dafb00877093170John Hoford        public VNode(VNode n) {
18325c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mType = n.mType;
18335c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mParams = Arrays.copyOf(n.mParams, n.mParams.length);
1834abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1835abb7d134c02ac60091108c491dafb00877093170John Hoford
1836abb7d134c02ac60091108c491dafb00877093170John Hoford        public VNode(VNode n1, VNode n2, float t) {
18375c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mType = n1.mType;
18385c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mParams = new float[n1.mParams.length];
1839abb7d134c02ac60091108c491dafb00877093170John Hoford            interpolate(n1, n2, t);
1840abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1841abb7d134c02ac60091108c491dafb00877093170John Hoford
1842abb7d134c02ac60091108c491dafb00877093170John Hoford        private boolean match(VNode n) {
18435c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            if (n.mType != mType) {
1844abb7d134c02ac60091108c491dafb00877093170John Hoford                return false;
1845abb7d134c02ac60091108c491dafb00877093170John Hoford            }
18465c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return (mParams.length == n.mParams.length);
1847abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1848abb7d134c02ac60091108c491dafb00877093170John Hoford
1849abb7d134c02ac60091108c491dafb00877093170John Hoford        public void interpolate(VNode n1, VNode n2, float t) {
18505c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            for (int i = 0; i < n1.mParams.length; i++) {
18515c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mParams[i] = n1.mParams[i] * (1 - t) + n2.mParams[i] * t;
1852abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1853abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1854abb7d134c02ac60091108c491dafb00877093170John Hoford
1855abb7d134c02ac60091108c491dafb00877093170John Hoford        private void nodeListToPath(VNode[] node, Path path) {
1856abb7d134c02ac60091108c491dafb00877093170John Hoford            float[] current = new float[4];
1857abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < node.length; i++) {
18585c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                addCommand(path, current, node[i].mType, node[i].mParams);
1859abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1860abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1861abb7d134c02ac60091108c491dafb00877093170John Hoford
1862abb7d134c02ac60091108c491dafb00877093170John Hoford        public static void createPath(VNode[] node, Path path) {
18635c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            float[] current = new float[4];
1864abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < node.length; i++) {
18655c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                addCommand(path, current, node[i].mType, node[i].mParams);
1866abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1867abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1868abb7d134c02ac60091108c491dafb00877093170John Hoford
1869abb7d134c02ac60091108c491dafb00877093170John Hoford        private static void addCommand(Path path, float[] current, char cmd, float[] val) {
1870abb7d134c02ac60091108c491dafb00877093170John Hoford
1871abb7d134c02ac60091108c491dafb00877093170John Hoford            int incr = 2;
1872abb7d134c02ac60091108c491dafb00877093170John Hoford            float currentX = current[0];
1873abb7d134c02ac60091108c491dafb00877093170John Hoford            float currentY = current[1];
1874abb7d134c02ac60091108c491dafb00877093170John Hoford            float ctrlPointX = current[2];
1875abb7d134c02ac60091108c491dafb00877093170John Hoford            float ctrlPointY = current[3];
1876abb7d134c02ac60091108c491dafb00877093170John Hoford
1877abb7d134c02ac60091108c491dafb00877093170John Hoford            switch (cmd) {
1878abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'z':
1879abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'Z':
1880abb7d134c02ac60091108c491dafb00877093170John Hoford                    path.close();
1881abb7d134c02ac60091108c491dafb00877093170John Hoford                    return;
1882abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'm':
1883abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'M':
1884abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'l':
1885abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'L':
1886abb7d134c02ac60091108c491dafb00877093170John Hoford                case 't':
1887abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'T':
1888abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 2;
1889abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1890abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'h':
1891abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'H':
1892abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'v':
1893abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'V':
1894abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 1;
1895abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1896abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'c':
1897abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'C':
1898abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 6;
1899abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1900abb7d134c02ac60091108c491dafb00877093170John Hoford                case 's':
1901abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'S':
1902abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'q':
1903abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'Q':
1904abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 4;
1905abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1906abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'a':
1907abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'A':
1908abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 7;
1909abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1910abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1911abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int k = 0; k < val.length; k += incr) {
1912abb7d134c02ac60091108c491dafb00877093170John Hoford                // TODO: build test to prove all permutations work
1913abb7d134c02ac60091108c491dafb00877093170John Hoford                switch (cmd) {
1914abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'm': // moveto - Start a new sub-path (relative)
1915abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rMoveTo(val[k + 0], val[k + 1]);
1916abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1917abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1918abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1919abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'M': // moveto - Start a new sub-path
1920abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.moveTo(val[k + 0], val[k + 1]);
1921abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1922abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 1];
1923abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1924abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'l': // lineto - Draw a line from the current point (relative)
1925abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(val[k + 0], val[k + 1]);
1926abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1927abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1928abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1929abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'L': // lineto - Draw a line from the current point
1930abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(val[k + 0], val[k + 1]);
1931abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1932abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 1];
1933abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1934abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'z': // closepath - Close the current subpath
1935abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'Z': // closepath - Close the current subpath
1936abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.close();
1937abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1938abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'h': // horizontal lineto - Draws a horizontal line (relative)
1939abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(val[k + 0], 0);
1940abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1941abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1942abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'H': // horizontal lineto - Draws a horizontal line
1943abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(val[k + 0], currentY);
1944abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1945abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1946abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'v': // vertical lineto - Draws a vertical line from the current point (r)
1947abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(0, val[k + 0]);
1948abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 0];
1949abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1950abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'V': // vertical lineto - Draws a vertical line from the current point
1951abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(currentX, val[k + 0]);
1952abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 0];
1953abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1954abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'c': // curveto - Draws a cubic Bézier curve (relative)
1955abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rCubicTo(val[k + 0],
1956abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
1957abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
1958abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3],
1959abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 4],
1960abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 5]);
1961abb7d134c02ac60091108c491dafb00877093170John Hoford
1962abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX + val[k + 2];
1963abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY + val[k + 3];
1964abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 4];
1965abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 5];
1966abb7d134c02ac60091108c491dafb00877093170John Hoford
1967abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1968abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'C': // curveto - Draws a cubic Bézier curve
1969abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.cubicTo(val[k + 0],
1970abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
1971abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
1972abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3],
1973abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 4],
1974abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 5]);
1975abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 4];
1976abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 5];
1977abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 2];
1978abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 3];
1979abb7d134c02ac60091108c491dafb00877093170John Hoford
1980abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1981abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp)
1982abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rCubicTo(currentX - ctrlPointX, currentY  - ctrlPointY,
1983abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1],
1984abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2], val[k + 3]);
1985abb7d134c02ac60091108c491dafb00877093170John Hoford
1986abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX + val[k + 0];
1987abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY + val[k + 1];
1988abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 2];
1989abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 3];
1990abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1991abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp)
1992abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.cubicTo(2 * currentX - ctrlPointX,
1993abb7d134c02ac60091108c491dafb00877093170John Hoford                                2 * currentY - ctrlPointY,
1994abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0],
1995abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
1996abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
1997abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3]);
1998abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 2];
1999abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 3];
2000abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 0];
2001abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 1];
2002abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
2003abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'q': // Draws a quadratic Bézier (relative)
2004abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
2005abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 2];
2006abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 3];
2007abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 0];
2008abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 1];
2009abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
2010abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'Q': // Draws a quadratic Bézier
2011abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
2012abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 2];
2013abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 3];
2014abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 0];
2015abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 1];
2016abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
2017abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 't': // Draws a quadratic Bézier curve(reflective control point)(relative)
2018abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rQuadTo(currentX - ctrlPointX, currentY - ctrlPointY,
2019abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1]);
2020abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = ctrlPointX + currentX;
2021abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = ctrlPointY + currentY;
2022abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
2023abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
2024abb7d134c02ac60091108c491dafb00877093170John Hoford
2025abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
2026abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'T': // Draws a quadratic Bézier curve (reflective control point)
2027abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.quadTo(currentX * 2 - ctrlPointX, currentY * 2 - ctrlPointY,
2028abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1]);
2029abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
2030abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 1]; // TODO: Check this logic
2031abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = -(val[k + 0] - currentX);
2032abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = -(val[k + 1] - currentY);
2033abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
2034abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'a': // Draws an elliptical arc
2035abb7d134c02ac60091108c491dafb00877093170John Hoford                        // (rx ry x-axis-rotation large-arc-flag sweep-flag x y)
2036abb7d134c02ac60091108c491dafb00877093170John Hoford                        drawArc(path,
2037abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentX,
2038abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentY,
2039abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 5] + currentX,
2040abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 6] + currentY,
2041abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0],
2042abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
2043abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
2044abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3] != 0,
2045abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 4] != 0);
2046abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 5];
2047abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 6];
2048abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX;
2049abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY;
2050abb7d134c02ac60091108c491dafb00877093170John Hoford
2051abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
2052abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'A': // Draws an elliptical arc
2053abb7d134c02ac60091108c491dafb00877093170John Hoford                        drawArc(path,
2054abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentX,
2055abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentY,
2056abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 5],
2057abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 6],
2058abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0],
2059abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
2060abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
2061abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3] != 0,
2062abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 4] != 0);
2063abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 5];
2064abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 6];
2065abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX;
2066abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY;
2067abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
2068abb7d134c02ac60091108c491dafb00877093170John Hoford                }
2069abb7d134c02ac60091108c491dafb00877093170John Hoford            }
2070abb7d134c02ac60091108c491dafb00877093170John Hoford            current[0] = currentX;
2071abb7d134c02ac60091108c491dafb00877093170John Hoford            current[1] = currentY;
2072abb7d134c02ac60091108c491dafb00877093170John Hoford            current[2] = ctrlPointX;
2073abb7d134c02ac60091108c491dafb00877093170John Hoford            current[3] = ctrlPointY;
2074abb7d134c02ac60091108c491dafb00877093170John Hoford        }
2075abb7d134c02ac60091108c491dafb00877093170John Hoford
2076abb7d134c02ac60091108c491dafb00877093170John Hoford        private static void drawArc(Path p,
2077abb7d134c02ac60091108c491dafb00877093170John Hoford                float x0,
2078abb7d134c02ac60091108c491dafb00877093170John Hoford                float y0,
2079abb7d134c02ac60091108c491dafb00877093170John Hoford                float x1,
2080abb7d134c02ac60091108c491dafb00877093170John Hoford                float y1,
2081abb7d134c02ac60091108c491dafb00877093170John Hoford                float a,
2082abb7d134c02ac60091108c491dafb00877093170John Hoford                float b,
2083abb7d134c02ac60091108c491dafb00877093170John Hoford                float theta,
2084abb7d134c02ac60091108c491dafb00877093170John Hoford                boolean isMoreThanHalf,
2085abb7d134c02ac60091108c491dafb00877093170John Hoford                boolean isPositiveArc) {
2086abb7d134c02ac60091108c491dafb00877093170John Hoford
2087abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Convert rotation angle from degrees to radians */
2088abb7d134c02ac60091108c491dafb00877093170John Hoford            double thetaD = Math.toRadians(theta);
2089abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Pre-compute rotation matrix entries */
2090abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosTheta = Math.cos(thetaD);
2091abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinTheta = Math.sin(thetaD);
2092abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Transform (x0, y0) and (x1, y1) into unit space */
2093abb7d134c02ac60091108c491dafb00877093170John Hoford            /* using (inverse) rotation, followed by (inverse) scale */
2094abb7d134c02ac60091108c491dafb00877093170John Hoford            double x0p = (x0 * cosTheta + y0 * sinTheta) / a;
2095abb7d134c02ac60091108c491dafb00877093170John Hoford            double y0p = (-x0 * sinTheta + y0 * cosTheta) / b;
2096abb7d134c02ac60091108c491dafb00877093170John Hoford            double x1p = (x1 * cosTheta + y1 * sinTheta) / a;
2097abb7d134c02ac60091108c491dafb00877093170John Hoford            double y1p = (-x1 * sinTheta + y1 * cosTheta) / b;
2098abb7d134c02ac60091108c491dafb00877093170John Hoford
2099abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Compute differences and averages */
2100abb7d134c02ac60091108c491dafb00877093170John Hoford            double dx = x0p - x1p;
2101abb7d134c02ac60091108c491dafb00877093170John Hoford            double dy = y0p - y1p;
2102abb7d134c02ac60091108c491dafb00877093170John Hoford            double xm = (x0p + x1p) / 2;
2103abb7d134c02ac60091108c491dafb00877093170John Hoford            double ym = (y0p + y1p) / 2;
2104abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Solve for intersecting unit circles */
2105abb7d134c02ac60091108c491dafb00877093170John Hoford            double dsq = dx * dx + dy * dy;
2106abb7d134c02ac60091108c491dafb00877093170John Hoford            if (dsq == 0.0) {
2107abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.w(LOGTAG, " Points are coincident");
2108abb7d134c02ac60091108c491dafb00877093170John Hoford                return; /* Points are coincident */
2109abb7d134c02ac60091108c491dafb00877093170John Hoford            }
2110abb7d134c02ac60091108c491dafb00877093170John Hoford            double disc = 1.0 / dsq - 1.0 / 4.0;
2111abb7d134c02ac60091108c491dafb00877093170John Hoford            if (disc < 0.0) {
2112abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.w(LOGTAG, "Points are too far apart " + dsq);
2113abb7d134c02ac60091108c491dafb00877093170John Hoford                float adjust = (float) (Math.sqrt(dsq) / 1.99999);
2114abb7d134c02ac60091108c491dafb00877093170John Hoford                drawArc(p, x0, y0, x1, y1, a * adjust,
2115abb7d134c02ac60091108c491dafb00877093170John Hoford                        b * adjust, theta, isMoreThanHalf, isPositiveArc);
2116abb7d134c02ac60091108c491dafb00877093170John Hoford                return; /* Points are too far apart */
2117abb7d134c02ac60091108c491dafb00877093170John Hoford            }
2118abb7d134c02ac60091108c491dafb00877093170John Hoford            double s = Math.sqrt(disc);
2119abb7d134c02ac60091108c491dafb00877093170John Hoford            double sdx = s * dx;
2120abb7d134c02ac60091108c491dafb00877093170John Hoford            double sdy = s * dy;
2121abb7d134c02ac60091108c491dafb00877093170John Hoford            double cx;
2122abb7d134c02ac60091108c491dafb00877093170John Hoford            double cy;
2123abb7d134c02ac60091108c491dafb00877093170John Hoford            if (isMoreThanHalf == isPositiveArc) {
2124abb7d134c02ac60091108c491dafb00877093170John Hoford                cx = xm - sdy;
2125abb7d134c02ac60091108c491dafb00877093170John Hoford                cy = ym + sdx;
2126abb7d134c02ac60091108c491dafb00877093170John Hoford            } else {
2127abb7d134c02ac60091108c491dafb00877093170John Hoford                cx = xm + sdy;
2128abb7d134c02ac60091108c491dafb00877093170John Hoford                cy = ym - sdx;
2129abb7d134c02ac60091108c491dafb00877093170John Hoford            }
2130abb7d134c02ac60091108c491dafb00877093170John Hoford
2131abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta0 = Math.atan2((y0p - cy), (x0p - cx));
2132abb7d134c02ac60091108c491dafb00877093170John Hoford
2133abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta1 = Math.atan2((y1p - cy), (x1p - cx));
2134abb7d134c02ac60091108c491dafb00877093170John Hoford
2135abb7d134c02ac60091108c491dafb00877093170John Hoford            double sweep = (eta1 - eta0);
2136abb7d134c02ac60091108c491dafb00877093170John Hoford            if (isPositiveArc != (sweep >= 0)) {
2137abb7d134c02ac60091108c491dafb00877093170John Hoford                if (sweep > 0) {
2138abb7d134c02ac60091108c491dafb00877093170John Hoford                    sweep -= 2 * Math.PI;
2139abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
2140abb7d134c02ac60091108c491dafb00877093170John Hoford                    sweep += 2 * Math.PI;
2141abb7d134c02ac60091108c491dafb00877093170John Hoford                }
2142abb7d134c02ac60091108c491dafb00877093170John Hoford            }
2143abb7d134c02ac60091108c491dafb00877093170John Hoford
2144abb7d134c02ac60091108c491dafb00877093170John Hoford            cx *= a;
2145abb7d134c02ac60091108c491dafb00877093170John Hoford            cy *= b;
2146abb7d134c02ac60091108c491dafb00877093170John Hoford            double tcx = cx;
2147abb7d134c02ac60091108c491dafb00877093170John Hoford            cx = cx * cosTheta - cy * sinTheta;
2148abb7d134c02ac60091108c491dafb00877093170John Hoford            cy = tcx * sinTheta + cy * cosTheta;
2149abb7d134c02ac60091108c491dafb00877093170John Hoford
2150abb7d134c02ac60091108c491dafb00877093170John Hoford            arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep);
2151abb7d134c02ac60091108c491dafb00877093170John Hoford        }
2152abb7d134c02ac60091108c491dafb00877093170John Hoford
2153abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
2154abb7d134c02ac60091108c491dafb00877093170John Hoford         * Converts an arc to cubic Bezier segments and records them in p.
2155abb7d134c02ac60091108c491dafb00877093170John Hoford         *
2156abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param p The target for the cubic Bezier segments
2157abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param cx The x coordinate center of the ellipse
2158abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param cy The y coordinate center of the ellipse
2159abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param a The radius of the ellipse in the horizontal direction
2160abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param b The radius of the ellipse in the vertical direction
2161abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param e1x E(eta1) x coordinate of the starting point of the arc
2162abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param e1y E(eta2) y coordinate of the starting point of the arc
2163abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param theta The angle that the ellipse bounding rectangle makes with horizontal plane
2164abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param start The start angle of the arc on the ellipse
2165abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse
2166abb7d134c02ac60091108c491dafb00877093170John Hoford         */
2167abb7d134c02ac60091108c491dafb00877093170John Hoford        private static void arcToBezier(Path p,
2168abb7d134c02ac60091108c491dafb00877093170John Hoford                double cx,
2169abb7d134c02ac60091108c491dafb00877093170John Hoford                double cy,
2170abb7d134c02ac60091108c491dafb00877093170John Hoford                double a,
2171abb7d134c02ac60091108c491dafb00877093170John Hoford                double b,
2172abb7d134c02ac60091108c491dafb00877093170John Hoford                double e1x,
2173abb7d134c02ac60091108c491dafb00877093170John Hoford                double e1y,
2174abb7d134c02ac60091108c491dafb00877093170John Hoford                double theta,
2175abb7d134c02ac60091108c491dafb00877093170John Hoford                double start,
2176abb7d134c02ac60091108c491dafb00877093170John Hoford                double sweep) {
2177abb7d134c02ac60091108c491dafb00877093170John Hoford            // Taken from equations at: http://spaceroots.org/documents/ellipse/node8.html
2178abb7d134c02ac60091108c491dafb00877093170John Hoford            // and http://www.spaceroots.org/documents/ellipse/node22.html
2179abb7d134c02ac60091108c491dafb00877093170John Hoford
2180abb7d134c02ac60091108c491dafb00877093170John Hoford            // Maximum of 45 degrees per cubic Bezier segment
2181abb7d134c02ac60091108c491dafb00877093170John Hoford            int numSegments = Math.abs((int) Math.ceil(sweep * 4 / Math.PI));
2182abb7d134c02ac60091108c491dafb00877093170John Hoford
2183abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta1 = start;
2184abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosTheta = Math.cos(theta);
2185abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinTheta = Math.sin(theta);
2186abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosEta1 = Math.cos(eta1);
2187abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinEta1 = Math.sin(eta1);
2188abb7d134c02ac60091108c491dafb00877093170John Hoford            double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1);
2189abb7d134c02ac60091108c491dafb00877093170John Hoford            double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1);
2190abb7d134c02ac60091108c491dafb00877093170John Hoford
2191abb7d134c02ac60091108c491dafb00877093170John Hoford            double anglePerSegment = sweep / numSegments;
2192abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < numSegments; i++) {
2193abb7d134c02ac60091108c491dafb00877093170John Hoford                double eta2 = eta1 + anglePerSegment;
2194abb7d134c02ac60091108c491dafb00877093170John Hoford                double sinEta2 = Math.sin(eta2);
2195abb7d134c02ac60091108c491dafb00877093170John Hoford                double cosEta2 = Math.cos(eta2);
2196abb7d134c02ac60091108c491dafb00877093170John Hoford                double e2x = cx + (a * cosTheta * cosEta2) - (b * sinTheta * sinEta2);
2197abb7d134c02ac60091108c491dafb00877093170John Hoford                double e2y = cy + (a * sinTheta * cosEta2) + (b * cosTheta * sinEta2);
2198abb7d134c02ac60091108c491dafb00877093170John Hoford                double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2;
2199abb7d134c02ac60091108c491dafb00877093170John Hoford                double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2;
2200abb7d134c02ac60091108c491dafb00877093170John Hoford                double tanDiff2 = Math.tan((eta2 - eta1) / 2);
2201abb7d134c02ac60091108c491dafb00877093170John Hoford                double alpha =
2202abb7d134c02ac60091108c491dafb00877093170John Hoford                        Math.sin(eta2 - eta1) * (Math.sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3;
2203abb7d134c02ac60091108c491dafb00877093170John Hoford                double q1x = e1x + alpha * ep1x;
2204abb7d134c02ac60091108c491dafb00877093170John Hoford                double q1y = e1y + alpha * ep1y;
2205abb7d134c02ac60091108c491dafb00877093170John Hoford                double q2x = e2x - alpha * ep2x;
2206abb7d134c02ac60091108c491dafb00877093170John Hoford                double q2y = e2y - alpha * ep2y;
2207abb7d134c02ac60091108c491dafb00877093170John Hoford
2208abb7d134c02ac60091108c491dafb00877093170John Hoford                p.cubicTo((float) q1x,
2209abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q1y,
2210abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q2x,
2211abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q2y,
2212abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) e2x,
2213abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) e2y);
2214abb7d134c02ac60091108c491dafb00877093170John Hoford                eta1 = eta2;
2215abb7d134c02ac60091108c491dafb00877093170John Hoford                e1x = e2x;
2216abb7d134c02ac60091108c491dafb00877093170John Hoford                e1y = e2y;
2217abb7d134c02ac60091108c491dafb00877093170John Hoford                ep1x = ep2x;
2218abb7d134c02ac60091108c491dafb00877093170John Hoford                ep1y = ep2y;
2219abb7d134c02ac60091108c491dafb00877093170John Hoford            }
2220abb7d134c02ac60091108c491dafb00877093170John Hoford        }
2221abb7d134c02ac60091108c491dafb00877093170John Hoford
2222abb7d134c02ac60091108c491dafb00877093170John Hoford    }
2223abb7d134c02ac60091108c491dafb00877093170John Hoford}
2224