VectorDrawable.java revision 175f3c892c2c0bd64e32484a2b430e7c59907243
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.Resources.Theme;
214b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viveretteimport android.content.res.TypedArray;
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;
334b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viveretteimport 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;
424b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viveretteimport 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;
504b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
51abb7d134c02ac60091108c491dafb00877093170John Hoford/**
52abb7d134c02ac60091108c491dafb00877093170John Hoford * This lets you create a drawable based on an XML vector graphic
53abb7d134c02ac60091108c491dafb00877093170John Hoford * It can be defined in an XML file with the <code>&lt;vector></code> element.
54abb7d134c02ac60091108c491dafb00877093170John Hoford * <p/>
55abb7d134c02ac60091108c491dafb00877093170John Hoford * The vector drawable has 6 elements:
56abb7d134c02ac60091108c491dafb00877093170John Hoford * <p/>
57abb7d134c02ac60091108c491dafb00877093170John Hoford * <dl>
58177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui * <dt><code>&lt;vector></code></dt>
59fba3bad3870d607ecaed4f147788885c841c2ab3ztenghui * <dd>The attribute <code>android:trigger</code> defines a state change that
60abb7d134c02ac60091108c491dafb00877093170John Hoford * will drive the animation </dd>
61fba3bad3870d607ecaed4f147788885c841c2ab3ztenghui * <dd>The attribute <code>android:versionCode</code> defines the version of
62177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui * VectorDrawable </dd>
63abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;size></code></dt>
64abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Used to defined the intrinsic Width Height size of the drawable using
65abb7d134c02ac60091108c491dafb00877093170John Hoford * <code>android:width</code> and <code>android:height</code> </dd>
66abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;viewport></code></dt>
67abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Used to defined the size of the virtual canvas the paths are drawn on.
68abb7d134c02ac60091108c491dafb00877093170John Hoford * The size is defined using the attributes <code>android:viewportHeight
69abb7d134c02ac60091108c491dafb00877093170John Hoford * </code> <code>android:viewportWidth</code></dd>
70abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;group></code></dt>
71abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines a "key frame" in the animation if there is only one group the
72abb7d134c02ac60091108c491dafb00877093170John Hoford * drawable is static 2D image that has no animation.</dd>
73abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;path></code></dt>
74abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines paths to be drawn. The path elements must be within a group
75abb7d134c02ac60091108c491dafb00877093170John Hoford * <dl>
76abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:name</code>
77abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines the name of the path.</dd></dt>
78abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pathData</code>
79abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines path string.</dd></dt>
80abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:fill</code>
81abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines the color to fill the path (none if not present).</dd></dt>
82abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:stroke</code>
83abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines the color to draw the path outline (none if not present).</dd></dt>
84abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeWidth</code>
85abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The width a path stroke</dd></dt>
86abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeOpacity</code>
87abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The opacity of a path stroke</dd></dt>
88abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:rotation</code>
89abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The amount to rotation the path stroke.</dd></dt>
90abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pivotX</code>
91abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The X coordinate of the center of rotation of a path</dd></dt>
92abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pivotY</code>
93abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The Y coordinate of the center of rotation of a path</dd></dt>
94abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:fillOpacity</code>
95abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The opacity to fill the path with</dd></dt>
96abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathStart</code>
97abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The fraction of the path to trim from the start from 0 to 1</dd></dt>
98abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathEnd</code>
99abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The fraction of the path to trim from the end from 0 to 1</dd></dt>
100abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathOffset</code>
101abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Shift trim region (allows showed region to include the start and end) from 0 to 1</dd></dt>
102abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:clipToPath</code>
103abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Path will set the clip path</dd></dt>
104abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeLineCap</code>
105abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the linecap for a stroked path: butt, round, square</dd></dt>
106abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeLineJoin</code>
107abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the lineJoin for a stroked path: miter,round,bevel</dd></dt>
108abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeMiterLimit</code>
109abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the Miter limit for a stroked path</dd></dt>
110abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_pressed</code>
111abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
112abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_focused</code>
113abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
114abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_selected</code>
115abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
116abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_window_focused</code>
117abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
118abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_enabled</code>
119abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
120abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_activated</code>
121abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
122abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_accelerated</code>
123abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
124abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_hovered</code>
125abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
126abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_checked</code>
127abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
128abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_checkable</code>
129abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
130abb7d134c02ac60091108c491dafb00877093170John Hoford * </dl>
131abb7d134c02ac60091108c491dafb00877093170John Hoford * </dd>
132abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;animation></code></dt>
133abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Used to customize the transition between two paths
134abb7d134c02ac60091108c491dafb00877093170John Hoford * <dl>
135abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:sequence</code>
136abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Configures this animation sequence between the named paths.</dd></dt>
137abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:limitTo</code>
138abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Limits an animation to only interpolate the selected variable
139abb7d134c02ac60091108c491dafb00877093170John Hoford * unlimited, path, rotation, trimPathStart, trimPathEnd, trimPathOffset</dd></dt>
140abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:repeatCount</code>
141abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Number of times to loop this aspect of the animation</dd></dt>
142abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:durations</code>
143abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The duration of each step in the animation in milliseconds
144abb7d134c02ac60091108c491dafb00877093170John Hoford * Must contain the number of named paths - 1</dd></dt>
145abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:startDelay</code>
146abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd></dd></dt>
147abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:repeatStyle</code>
148abb7d134c02ac60091108c491dafb00877093170John Hoford *  <dd>when repeating how does it repeat back and forth or a to b: forward, inAndOut</dd></dt>
149abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:animate</code>
150abb7d134c02ac60091108c491dafb00877093170John Hoford *  <dd>linear, accelerate, decelerate, easing</dd></dt>
151abb7d134c02ac60091108c491dafb00877093170John Hoford * </dl>
152abb7d134c02ac60091108c491dafb00877093170John Hoford * </dd>
153abb7d134c02ac60091108c491dafb00877093170John Hoford */
154abb7d134c02ac60091108c491dafb00877093170John Hofordpublic class VectorDrawable extends Drawable {
1559453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    private static final String LOGTAG = VectorDrawable.class.getSimpleName();
1569453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
157abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_SIZE = "size";
158abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_VIEWPORT = "viewport";
159abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_GROUP = "group";
160abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_PATH = "path";
161abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_TRANSITION = "transition";
162abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_ANIMATION = "animation";
163abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_VECTOR = "vector";
164abb7d134c02ac60091108c491dafb00877093170John Hoford
165abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINECAP_BUTT = 0;
166abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINECAP_ROUND = 1;
167abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINECAP_SQUARE = 2;
1689453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
169abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINEJOIN_MITER = 0;
170abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINEJOIN_ROUND = 1;
171abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINEJOIN_BEVEL = 2;
1729453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
173abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int DEFAULT_DURATION = 1000;
174abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final long DEFAULT_INFINITE_DURATION = 60 * 60 * 1000;
1759453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1764b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette    private final VectorDrawableState mVectorState;
1774b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
178abb7d134c02ac60091108c491dafb00877093170John Hoford    private int mAlpha = 0xFF;
179abb7d134c02ac60091108c491dafb00877093170John Hoford
180abb7d134c02ac60091108c491dafb00877093170John Hoford    public VectorDrawable() {
1819453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        mVectorState = new VectorDrawableState(null);
182abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mBasicAnimator = ObjectAnimator.ofFloat(this, "AnimationFraction", 0, 1);
1839453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
184abb7d134c02ac60091108c491dafb00877093170John Hoford        setDuration(DEFAULT_DURATION);
185abb7d134c02ac60091108c491dafb00877093170John Hoford    }
186abb7d134c02ac60091108c491dafb00877093170John Hoford
1879453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    private VectorDrawable(VectorDrawableState state, Resources res, Theme theme) {
188abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState = new VectorDrawableState(state);
189abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mBasicAnimator = ObjectAnimator.ofFloat(this, "AnimationFraction", 0, 1);
1909453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1919453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        if (theme != null && canApplyTheme()) {
1929453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            applyTheme(theme);
1939453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
1949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
195abb7d134c02ac60091108c491dafb00877093170John Hoford        long duration = mVectorState.mVAnimatedPath.getTotalAnimationDuration();
196abb7d134c02ac60091108c491dafb00877093170John Hoford        if (duration == -1) { // if it set to infinite set to 1 hour
197abb7d134c02ac60091108c491dafb00877093170John Hoford            duration = DEFAULT_INFINITE_DURATION; // TODO define correct approach for infinite
198abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mBasicAnimator.setFloatValues(0, duration / 1000);
199abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mBasicAnimator.setInterpolator(new LinearInterpolator());
200abb7d134c02ac60091108c491dafb00877093170John Hoford        }
201abb7d134c02ac60091108c491dafb00877093170John Hoford        setDuration(duration);
202abb7d134c02ac60091108c491dafb00877093170John Hoford    }
203abb7d134c02ac60091108c491dafb00877093170John Hoford
204abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
205abb7d134c02ac60091108c491dafb00877093170John Hoford    public ConstantState getConstantState() {
206abb7d134c02ac60091108c491dafb00877093170John Hoford        return mVectorState;
207abb7d134c02ac60091108c491dafb00877093170John Hoford    }
208abb7d134c02ac60091108c491dafb00877093170John Hoford
209abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
2105c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * Starts the animation.
211abb7d134c02ac60091108c491dafb00877093170John Hoford     */
212abb7d134c02ac60091108c491dafb00877093170John Hoford    public void start() {
213abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mBasicAnimator.start();
214abb7d134c02ac60091108c491dafb00877093170John Hoford    }
215abb7d134c02ac60091108c491dafb00877093170John Hoford
216abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
2175c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * Stops the animation.
218abb7d134c02ac60091108c491dafb00877093170John Hoford     */
219abb7d134c02ac60091108c491dafb00877093170John Hoford    public void stop() {
220abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mBasicAnimator.end();
221abb7d134c02ac60091108c491dafb00877093170John Hoford    }
222abb7d134c02ac60091108c491dafb00877093170John Hoford
223abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
2245c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * Returns the current completion value for the animation.
225abb7d134c02ac60091108c491dafb00877093170John Hoford     *
2265c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * @return the current point on the animation, typically between 0 and 1
227abb7d134c02ac60091108c491dafb00877093170John Hoford     */
228abb7d134c02ac60091108c491dafb00877093170John Hoford    public float geAnimationFraction() {
229abb7d134c02ac60091108c491dafb00877093170John Hoford        return mVectorState.mVAnimatedPath.getValue();
230abb7d134c02ac60091108c491dafb00877093170John Hoford    }
231abb7d134c02ac60091108c491dafb00877093170John Hoford
232abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
2335c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * Set the current completion value for the animation.
234abb7d134c02ac60091108c491dafb00877093170John Hoford     *
2355c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * @param value the point along the animation, typically between 0 and 1
236abb7d134c02ac60091108c491dafb00877093170John Hoford     */
237abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setAnimationFraction(float value) {
238abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mVAnimatedPath.setAnimationFraction(value);
239abb7d134c02ac60091108c491dafb00877093170John Hoford        invalidateSelf();
240abb7d134c02ac60091108c491dafb00877093170John Hoford    }
241abb7d134c02ac60091108c491dafb00877093170John Hoford
242abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
243abb7d134c02ac60091108c491dafb00877093170John Hoford     * set the amount of time the animation will take
244abb7d134c02ac60091108c491dafb00877093170John Hoford     *
245abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param duration amount of time in milliseconds
246abb7d134c02ac60091108c491dafb00877093170John Hoford     */
247abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setDuration(long duration) {
248abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mBasicAnimator.setDuration(duration);
249abb7d134c02ac60091108c491dafb00877093170John Hoford    }
250abb7d134c02ac60091108c491dafb00877093170John Hoford
251abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
2525c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * Defines what this animation should do when it reaches the end. This
2535c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * setting is applied only when the repeat count is either greater than
2545c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * 0 or {@link ValueAnimator#INFINITE}.
2555c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     *
2565c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * @param mode the animation mode, either {@link ValueAnimator#RESTART}
2575c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     *        or {@link ValueAnimator#REVERSE}
258abb7d134c02ac60091108c491dafb00877093170John Hoford     */
259abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setRepeatMode(int mode) {
260abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mBasicAnimator.setRepeatMode(mode);
261abb7d134c02ac60091108c491dafb00877093170John Hoford    }
262abb7d134c02ac60091108c491dafb00877093170John Hoford
263abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
264abb7d134c02ac60091108c491dafb00877093170John Hoford     * Sets animation to repeat
265abb7d134c02ac60091108c491dafb00877093170John Hoford     *
266abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param repeat True if this drawable repeats its animation
267abb7d134c02ac60091108c491dafb00877093170John Hoford     */
268abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setRepeatCount(int repeat) {
269abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mBasicAnimator.setRepeatCount(repeat);
270abb7d134c02ac60091108c491dafb00877093170John Hoford    }
271abb7d134c02ac60091108c491dafb00877093170John Hoford
272abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
2735c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * @return the animation repeat count, either a value greater than 0 or
2745c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     *         {@link ValueAnimator#INFINITE}
275abb7d134c02ac60091108c491dafb00877093170John Hoford     */
276abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getRepeatCount() {
277abb7d134c02ac60091108c491dafb00877093170John Hoford        return mVectorState.mBasicAnimator.getRepeatCount();
278abb7d134c02ac60091108c491dafb00877093170John Hoford    }
279abb7d134c02ac60091108c491dafb00877093170John Hoford
280abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
281abb7d134c02ac60091108c491dafb00877093170John Hoford    public boolean isStateful() {
282abb7d134c02ac60091108c491dafb00877093170John Hoford        return true;
283abb7d134c02ac60091108c491dafb00877093170John Hoford    }
284abb7d134c02ac60091108c491dafb00877093170John Hoford
285abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
286abb7d134c02ac60091108c491dafb00877093170John Hoford    protected boolean onStateChange(int[] state) {
2874b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        super.onStateChange(state);
2884b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
289abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mVAnimatedPath.setState(state);
2904b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
2914b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        final int direction = mVectorState.mVAnimatedPath.getTrigger(state);
2924b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        if (direction > 0) {
293abb7d134c02ac60091108c491dafb00877093170John Hoford            animateForward();
2944b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        } else if (direction < 0) {
295abb7d134c02ac60091108c491dafb00877093170John Hoford            animateBackward();
296abb7d134c02ac60091108c491dafb00877093170John Hoford        }
2974b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
298abb7d134c02ac60091108c491dafb00877093170John Hoford        invalidateSelf();
299abb7d134c02ac60091108c491dafb00877093170John Hoford        return true;
300abb7d134c02ac60091108c491dafb00877093170John Hoford    }
301abb7d134c02ac60091108c491dafb00877093170John Hoford
302abb7d134c02ac60091108c491dafb00877093170John Hoford    private void animateForward(){
303abb7d134c02ac60091108c491dafb00877093170John Hoford        if (!mVectorState.mBasicAnimator.isStarted()) {
304abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mBasicAnimator.setFloatValues(0,1);
305abb7d134c02ac60091108c491dafb00877093170John Hoford            start();
306abb7d134c02ac60091108c491dafb00877093170John Hoford        }
307abb7d134c02ac60091108c491dafb00877093170John Hoford    }
308abb7d134c02ac60091108c491dafb00877093170John Hoford
309abb7d134c02ac60091108c491dafb00877093170John Hoford    private void animateBackward(){
310abb7d134c02ac60091108c491dafb00877093170John Hoford        if (!mVectorState.mBasicAnimator.isStarted()) {
311abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mBasicAnimator.setFloatValues(.99f,0);
312abb7d134c02ac60091108c491dafb00877093170John Hoford            start();
313abb7d134c02ac60091108c491dafb00877093170John Hoford        }
314abb7d134c02ac60091108c491dafb00877093170John Hoford    }
315abb7d134c02ac60091108c491dafb00877093170John Hoford
316abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
317abb7d134c02ac60091108c491dafb00877093170John Hoford    public void draw(Canvas canvas) {
3184b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        final int saveCount = canvas.save();
3194b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        final Rect bounds = getBounds();
3204b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        canvas.translate(bounds.left, bounds.top);
3214b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        mVectorState.mVAnimatedPath.draw(canvas, bounds.width(), bounds.height());
3224b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        canvas.restoreToCount(saveCount);
323abb7d134c02ac60091108c491dafb00877093170John Hoford    }
324abb7d134c02ac60091108c491dafb00877093170John Hoford
325abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
326abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setAlpha(int alpha) {
327abb7d134c02ac60091108c491dafb00877093170John Hoford        // TODO correct handling of transparent
328abb7d134c02ac60091108c491dafb00877093170John Hoford        if (mAlpha != alpha) {
329abb7d134c02ac60091108c491dafb00877093170John Hoford            mAlpha = alpha;
330abb7d134c02ac60091108c491dafb00877093170John Hoford            invalidateSelf();
331abb7d134c02ac60091108c491dafb00877093170John Hoford        }
332abb7d134c02ac60091108c491dafb00877093170John Hoford    }
333abb7d134c02ac60091108c491dafb00877093170John Hoford
334abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
335abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setColorFilter(ColorFilter colorFilter) {
336abb7d134c02ac60091108c491dafb00877093170John Hoford        // TODO: support color filter
337abb7d134c02ac60091108c491dafb00877093170John Hoford    }
338abb7d134c02ac60091108c491dafb00877093170John Hoford
339abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
340abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getOpacity() {
341abb7d134c02ac60091108c491dafb00877093170John Hoford        return PixelFormat.TRANSLUCENT;
342abb7d134c02ac60091108c491dafb00877093170John Hoford    }
343abb7d134c02ac60091108c491dafb00877093170John Hoford
344abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
345abb7d134c02ac60091108c491dafb00877093170John Hoford     * Sets padding for this shape, defined by a Rect object. Define the padding in the Rect object
346abb7d134c02ac60091108c491dafb00877093170John Hoford     * as: left, top, right, bottom.
347abb7d134c02ac60091108c491dafb00877093170John Hoford     */
348abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setPadding(Rect padding) {
349abb7d134c02ac60091108c491dafb00877093170John Hoford        setPadding(padding.left, padding.top, padding.right, padding.bottom);
350abb7d134c02ac60091108c491dafb00877093170John Hoford    }
351abb7d134c02ac60091108c491dafb00877093170John Hoford
352abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
353abb7d134c02ac60091108c491dafb00877093170John Hoford     * Sets padding for the shape.
354abb7d134c02ac60091108c491dafb00877093170John Hoford     *
355abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param left padding for the left side (in pixels)
356abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param top padding for the top (in pixels)
357abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param right padding for the right side (in pixels)
358abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param bottom padding for the bottom (in pixels)
359abb7d134c02ac60091108c491dafb00877093170John Hoford     */
360abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setPadding(int left, int top, int right, int bottom) {
361abb7d134c02ac60091108c491dafb00877093170John Hoford        if ((left | top | right | bottom) == 0) {
362abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mPadding = null;
363abb7d134c02ac60091108c491dafb00877093170John Hoford        } else {
364abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mVectorState.mPadding == null) {
365abb7d134c02ac60091108c491dafb00877093170John Hoford                mVectorState.mPadding = new Rect();
366abb7d134c02ac60091108c491dafb00877093170John Hoford            }
367abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mPadding.set(left, top, right, bottom);
368abb7d134c02ac60091108c491dafb00877093170John Hoford        }
369abb7d134c02ac60091108c491dafb00877093170John Hoford        invalidateSelf();
370abb7d134c02ac60091108c491dafb00877093170John Hoford    }
371abb7d134c02ac60091108c491dafb00877093170John Hoford
372abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
373abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getIntrinsicWidth() {
3744b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        return (int) mVectorState.mVAnimatedPath.mBaseWidth;
375abb7d134c02ac60091108c491dafb00877093170John Hoford    }
376abb7d134c02ac60091108c491dafb00877093170John Hoford
377abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
378abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getIntrinsicHeight() {
3794b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        return (int) mVectorState.mVAnimatedPath.mBaseHeight;
380abb7d134c02ac60091108c491dafb00877093170John Hoford    }
381abb7d134c02ac60091108c491dafb00877093170John Hoford
382abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
383abb7d134c02ac60091108c491dafb00877093170John Hoford    public boolean getPadding(Rect padding) {
384abb7d134c02ac60091108c491dafb00877093170John Hoford        if (mVectorState.mPadding != null) {
385abb7d134c02ac60091108c491dafb00877093170John Hoford            padding.set(mVectorState.mPadding);
386abb7d134c02ac60091108c491dafb00877093170John Hoford            return true;
387abb7d134c02ac60091108c491dafb00877093170John Hoford        } else {
388abb7d134c02ac60091108c491dafb00877093170John Hoford            return super.getPadding(padding);
389abb7d134c02ac60091108c491dafb00877093170John Hoford        }
390abb7d134c02ac60091108c491dafb00877093170John Hoford    }
391abb7d134c02ac60091108c491dafb00877093170John Hoford
392abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
393abb7d134c02ac60091108c491dafb00877093170John Hoford    public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
394abb7d134c02ac60091108c491dafb00877093170John Hoford            throws XmlPullParserException, IOException {
3959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        final VAnimatedPath p = inflateInternal(res, parser, attrs, theme);
3969453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        setAnimatedPath(p);
397abb7d134c02ac60091108c491dafb00877093170John Hoford    }
398abb7d134c02ac60091108c491dafb00877093170John Hoford
3999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    @Override
4009453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    public boolean canApplyTheme() {
4019453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        return super.canApplyTheme() || mVectorState != null && mVectorState.canApplyTheme();
4029453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    }
4039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
4049453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    @Override
4059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    public void applyTheme(Theme t) {
4069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        super.applyTheme(t);
4079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
4089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        final VectorDrawableState state = mVectorState;
4099453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        final VAnimatedPath path = state.mVAnimatedPath;
4109453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        if (path != null && path.canApplyTheme()) {
4119453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            path.applyTheme(t);
4129453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
4139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    }
4149453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
4154b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette    /** @hide */
4164b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette    public static VectorDrawable create(Resources resources, int rid) {
4174b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        try {
4184b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            final XmlPullParser xpp = resources.getXml(rid);
4194b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            final AttributeSet attrs = Xml.asAttributeSet(xpp);
4204b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            final XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
4214b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            factory.setNamespaceAware(true);
4224b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette
4234b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            final VectorDrawable drawable = new VectorDrawable();
4244b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            drawable.inflate(resources, xpp, attrs);
4254b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            drawable.setAnimationFraction(0);
4264b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette
4274b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            return drawable;
4284b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        } catch (XmlPullParserException e) {
4294b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            Log.e(LOGTAG, "parser error", e);
4304b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        } catch (IOException e) {
4314b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            Log.e(LOGTAG, "parser error", e);
4324b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        }
4334b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        return null;
4344b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette    }
4354b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette
4369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    private VAnimatedPath inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
4379453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            Theme theme) throws XmlPullParserException, IOException {
4389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        final VAnimatedPath animatedPath = new VAnimatedPath();
4399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
440abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noSizeTag = true;
441abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noViewportTag = true;
442abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noGroupTag = true;
443abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noPathTag = true;
4449453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
4459453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        VGroup currentGroup = null;
446abb7d134c02ac60091108c491dafb00877093170John Hoford
447abb7d134c02ac60091108c491dafb00877093170John Hoford        int eventType = parser.getEventType();
448abb7d134c02ac60091108c491dafb00877093170John Hoford        while (eventType != XmlPullParser.END_DOCUMENT) {
449abb7d134c02ac60091108c491dafb00877093170John Hoford            if (eventType == XmlPullParser.START_TAG) {
4509453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final String tagName = parser.getName();
451abb7d134c02ac60091108c491dafb00877093170John Hoford                if (SHAPE_PATH.equals(tagName)) {
4529453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final VPath path = new VPath();
4539453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    path.inflate(res, attrs, theme);
4549453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    currentGroup.add(path);
455abb7d134c02ac60091108c491dafb00877093170John Hoford                    noPathTag = false;
456abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_ANIMATION.equals(tagName)) {
4579453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final VAnimation anim = new VAnimation();
4589453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    anim.inflate(animatedPath.mGroupList, res, attrs, theme);
459abb7d134c02ac60091108c491dafb00877093170John Hoford                    animatedPath.addAnimation(anim);
460abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_SIZE.equals(tagName)) {
461abb7d134c02ac60091108c491dafb00877093170John Hoford                    animatedPath.parseSize(res, attrs);
462abb7d134c02ac60091108c491dafb00877093170John Hoford                    noSizeTag = false;
463abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_VIEWPORT.equals(tagName)) {
464abb7d134c02ac60091108c491dafb00877093170John Hoford                    animatedPath.parseViewport(res, attrs);
465abb7d134c02ac60091108c491dafb00877093170John Hoford                    noViewportTag = false;
466abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_GROUP.equals(tagName)) {
4679453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    currentGroup = new VGroup();
468abb7d134c02ac60091108c491dafb00877093170John Hoford                    animatedPath.mGroupList.add(currentGroup);
469abb7d134c02ac60091108c491dafb00877093170John Hoford                    noGroupTag = false;
470abb7d134c02ac60091108c491dafb00877093170John Hoford                }  else if (SHAPE_VECTOR.equals(tagName)) {
4719453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final TypedArray a = res.obtainAttributes(attrs, R.styleable.VectorDrawable);
472abb7d134c02ac60091108c491dafb00877093170John Hoford                    animatedPath.setTrigger(a.getInteger(R.styleable.VectorDrawable_trigger, 0));
473177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui
474177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    // Parsing the version information.
475177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    // Right now, we only support version "1".
476177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    // If the xml didn't specify the version number, the default version is "1".
4779453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final int versionCode = a.getInt(R.styleable.VectorDrawable_versionCode, 1);
478177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    if (versionCode != 1) {
479177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                        throw new IllegalArgumentException(
480177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                                "So far, VectorDrawable only support version 1");
481177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    }
482177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui
483abb7d134c02ac60091108c491dafb00877093170John Hoford                    a.recycle();
484abb7d134c02ac60091108c491dafb00877093170John Hoford                }
485abb7d134c02ac60091108c491dafb00877093170John Hoford            }
4869453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
487abb7d134c02ac60091108c491dafb00877093170John Hoford            eventType = parser.next();
488abb7d134c02ac60091108c491dafb00877093170John Hoford        }
4899453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
490abb7d134c02ac60091108c491dafb00877093170John Hoford        if (noSizeTag || noViewportTag || noGroupTag || noPathTag) {
4919453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final StringBuffer tag = new StringBuffer();
4929453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
493abb7d134c02ac60091108c491dafb00877093170John Hoford            if (noSizeTag) {
4949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_SIZE);
495abb7d134c02ac60091108c491dafb00877093170John Hoford            }
4969453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
497abb7d134c02ac60091108c491dafb00877093170John Hoford            if  (noViewportTag){
498abb7d134c02ac60091108c491dafb00877093170John Hoford                if (tag.length()>0) {
499abb7d134c02ac60091108c491dafb00877093170John Hoford                    tag.append(" & ");
500abb7d134c02ac60091108c491dafb00877093170John Hoford                }
5019453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_SIZE);
502abb7d134c02ac60091108c491dafb00877093170John Hoford            }
5039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
504abb7d134c02ac60091108c491dafb00877093170John Hoford            if  (noGroupTag){
505abb7d134c02ac60091108c491dafb00877093170John Hoford                if (tag.length()>0) {
506abb7d134c02ac60091108c491dafb00877093170John Hoford                    tag.append(" & ");
507abb7d134c02ac60091108c491dafb00877093170John Hoford                }
5089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_GROUP);
509abb7d134c02ac60091108c491dafb00877093170John Hoford            }
5109453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
511abb7d134c02ac60091108c491dafb00877093170John Hoford            if  (noPathTag){
512abb7d134c02ac60091108c491dafb00877093170John Hoford                if (tag.length()>0) {
513abb7d134c02ac60091108c491dafb00877093170John Hoford                    tag.append(" or ");
514abb7d134c02ac60091108c491dafb00877093170John Hoford                }
5159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_PATH);
516abb7d134c02ac60091108c491dafb00877093170John Hoford            }
5179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
5189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            throw new XmlPullParserException("no " + tag + " defined");
519abb7d134c02ac60091108c491dafb00877093170John Hoford        }
5209453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
521abb7d134c02ac60091108c491dafb00877093170John Hoford        // post parse cleanup
522abb7d134c02ac60091108c491dafb00877093170John Hoford        animatedPath.parseFinish();
523abb7d134c02ac60091108c491dafb00877093170John Hoford        return animatedPath;
524abb7d134c02ac60091108c491dafb00877093170John Hoford    }
525abb7d134c02ac60091108c491dafb00877093170John Hoford
526abb7d134c02ac60091108c491dafb00877093170John Hoford    private void setAnimatedPath(VAnimatedPath animatedPath) {
527abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mVAnimatedPath = animatedPath;
5289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
529abb7d134c02ac60091108c491dafb00877093170John Hoford        long duration = mVectorState.mVAnimatedPath.getTotalAnimationDuration();
530abb7d134c02ac60091108c491dafb00877093170John Hoford        if (duration == -1) { // if it set to infinite set to 1 hour
531abb7d134c02ac60091108c491dafb00877093170John Hoford            duration = DEFAULT_INFINITE_DURATION; // TODO define correct approach for infinite
532abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mBasicAnimator.setFloatValues(0, duration / 1000);
533abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mBasicAnimator.setInterpolator(new LinearInterpolator());
534abb7d134c02ac60091108c491dafb00877093170John Hoford        }
535abb7d134c02ac60091108c491dafb00877093170John Hoford
5369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        setDuration(duration);
537abb7d134c02ac60091108c491dafb00877093170John Hoford        setAnimationFraction(0);
538abb7d134c02ac60091108c491dafb00877093170John Hoford    }
539abb7d134c02ac60091108c491dafb00877093170John Hoford
540abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
541abb7d134c02ac60091108c491dafb00877093170John Hoford    public boolean setVisible(boolean visible, boolean restart) {
542abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean changed = super.setVisible(visible, restart);
543abb7d134c02ac60091108c491dafb00877093170John Hoford        if (visible) {
544abb7d134c02ac60091108c491dafb00877093170John Hoford            if (changed || restart) {
545abb7d134c02ac60091108c491dafb00877093170John Hoford                setAnimationFraction(0);
546abb7d134c02ac60091108c491dafb00877093170John Hoford            }
547abb7d134c02ac60091108c491dafb00877093170John Hoford        } else {
548abb7d134c02ac60091108c491dafb00877093170John Hoford            stop();
549abb7d134c02ac60091108c491dafb00877093170John Hoford        }
550abb7d134c02ac60091108c491dafb00877093170John Hoford        return changed;
551abb7d134c02ac60091108c491dafb00877093170John Hoford    }
552abb7d134c02ac60091108c491dafb00877093170John Hoford
5535c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette    private static class VectorDrawableState extends ConstantState {
5545c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        int mChangingConfigurations;
5555c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        ValueAnimator mBasicAnimator;
5565c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        VAnimatedPath mVAnimatedPath;
5575c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        Rect mPadding;
5585c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
5595c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public VectorDrawableState(VectorDrawableState copy) {
5605c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            if (copy != null) {
5615c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mChangingConfigurations = copy.mChangingConfigurations;
5625c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mVAnimatedPath = new VAnimatedPath(copy.mVAnimatedPath);
5635c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mPadding = new Rect(copy.mPadding);
5645c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            }
5655c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
5665c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
5675c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
5685c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable() {
5695c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, null, null);
5705c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
5715c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
5725c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
5735c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable(Resources res) {
5745c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, res, null);
5755c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
5765c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
5775c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
5785c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable(Resources res, Theme theme) {
5795c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, res, theme);
5805c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
5815c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
5825c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
5835c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public int getChangingConfigurations() {
5845c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return mChangingConfigurations;
5855c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
5865c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette    }
5875c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
588abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VAnimatedPath {
5894b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private static final int [] TRIGGER_MAP = {
5904b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                0,
5914b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                R.attr.state_pressed,
5924b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                R.attr.state_focused,
5934b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                R.attr.state_hovered,
5944b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                R.attr.state_selected,
5954b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                R.attr.state_checkable,
5964b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                R.attr.state_checked,
5974b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                R.attr.state_activated,
5984b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                R.attr.state_focused
5994b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        };
6004b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
6014b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private final Path mPath = new Path();
6024b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private final Path mRenderPath = new Path();
6034b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private final Matrix mMatrix = new Matrix();
6044b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
6054b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private ArrayList<VAnimation> mCurrentAnimList;
606abb7d134c02ac60091108c491dafb00877093170John Hoford        private VPath[] mCurrentPaths;
6074b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private Paint mStrokePaint;
6084b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private Paint mFillPaint;
609abb7d134c02ac60091108c491dafb00877093170John Hoford        private PathMeasure mPathMeasure;
6104b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
611abb7d134c02ac60091108c491dafb00877093170John Hoford        private int[] mCurrentState = new int[0];
6124b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private float mAnimationValue;
6134b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private long mTotalDuration;
614abb7d134c02ac60091108c491dafb00877093170John Hoford        private int mTrigger;
615abb7d134c02ac60091108c491dafb00877093170John Hoford        private boolean mTriggerState;
6169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        final ArrayList<VGroup> mGroupList = new ArrayList<VGroup>();
6189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
619abb7d134c02ac60091108c491dafb00877093170John Hoford        float mBaseWidth = 1;
620abb7d134c02ac60091108c491dafb00877093170John Hoford        float mBaseHeight = 1;
621abb7d134c02ac60091108c491dafb00877093170John Hoford        float mViewportWidth;
622abb7d134c02ac60091108c491dafb00877093170John Hoford        float mViewportHeight;
623abb7d134c02ac60091108c491dafb00877093170John Hoford
624abb7d134c02ac60091108c491dafb00877093170John Hoford        public VAnimatedPath() {
625abb7d134c02ac60091108c491dafb00877093170John Hoford        }
6269453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
627abb7d134c02ac60091108c491dafb00877093170John Hoford        public VAnimatedPath(VAnimatedPath copy) {
628abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentAnimList = new ArrayList<VAnimation>(copy.mCurrentAnimList);
6299453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            mGroupList.addAll(copy.mGroupList);
630abb7d134c02ac60091108c491dafb00877093170John Hoford            if (copy.mCurrentPaths != null) {
631abb7d134c02ac60091108c491dafb00877093170John Hoford                mCurrentPaths = new VPath[copy.mCurrentPaths.length];
632abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int i = 0; i < mCurrentPaths.length; i++) {
633abb7d134c02ac60091108c491dafb00877093170John Hoford                    mCurrentPaths[i] = new VPath(copy.mCurrentPaths[i]);
634abb7d134c02ac60091108c491dafb00877093170John Hoford                }
635abb7d134c02ac60091108c491dafb00877093170John Hoford            }
636abb7d134c02ac60091108c491dafb00877093170John Hoford            mAnimationValue = copy.mAnimationValue; // time goes from 0 to 1
637abb7d134c02ac60091108c491dafb00877093170John Hoford
638abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseWidth = copy.mBaseWidth;
639abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseHeight = copy.mBaseHeight;
640abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportWidth = copy.mViewportHeight;
641abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportHeight = copy.mViewportHeight;
642abb7d134c02ac60091108c491dafb00877093170John Hoford            mTotalDuration = copy.mTotalDuration;
643abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrigger = copy.mTrigger;
644abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentState = new int[0];
645abb7d134c02ac60091108c491dafb00877093170John Hoford        }
646abb7d134c02ac60091108c491dafb00877093170John Hoford
6479453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean canApplyTheme() {
6489453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final ArrayList<VGroup> groups = mGroupList;
6499453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            for (int i = groups.size() - 1; i >= 0; i--) {
6509453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final ArrayList<VPath> paths = groups.get(i).mVGList;
6519453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                for (int j = paths.size() - 1; j >= 0; j--) {
6529453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final VPath path = paths.get(j);
6539453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    if (path.canApplyTheme()) {
6549453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                        return true;
6559453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    }
6569453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
6579453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
6589453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6599453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final ArrayList<VAnimation> anims = mCurrentAnimList;
6609453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            for (int i = anims.size() - 1; i >= 0; i--) {
6619453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final VAnimation anim = anims.get(i);
6629453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                if (anim.canApplyTheme()) {
6639453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    return true;
6649453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
6659453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
6669453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6679453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return false;
6689453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
6699453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6709453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void applyTheme(Theme t) {
6719453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final ArrayList<VGroup> groups = mGroupList;
6729453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            for (int i = groups.size() - 1; i >= 0; i--) {
6739453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final ArrayList<VPath> paths = groups.get(i).mVGList;
6749453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                for (int j = paths.size() - 1; j >= 0; j--) {
6759453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final VPath path = paths.get(j);
6769453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    if (path.canApplyTheme()) {
6779453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                        path.applyTheme(t);
6789453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    }
6799453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
6809453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
6819453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6829453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final ArrayList<VAnimation> anims = mCurrentAnimList;
6839453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            for (int i = anims.size() - 1; i >= 0; i--) {
6849453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final VAnimation anim = anims.get(i);
6859453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                if (anim.canApplyTheme()) {
6869453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    anim.applyTheme(t);
6879453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
6889453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
6899453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
6909453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
691abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setTrigger(int trigger){
6924b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            mTrigger = VAnimatedPath.getStateForTrigger(trigger);
693abb7d134c02ac60091108c491dafb00877093170John Hoford        }
694abb7d134c02ac60091108c491dafb00877093170John Hoford
695abb7d134c02ac60091108c491dafb00877093170John Hoford        public long getTotalAnimationDuration() {
696abb7d134c02ac60091108c491dafb00877093170John Hoford            mTotalDuration = 0;
697abb7d134c02ac60091108c491dafb00877093170John Hoford            int size = mCurrentAnimList.size();
698abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < size; i++) {
699abb7d134c02ac60091108c491dafb00877093170John Hoford                VAnimation vAnimation = mCurrentAnimList.get(i);
700abb7d134c02ac60091108c491dafb00877093170John Hoford                long t = vAnimation.getTotalDuration();
701abb7d134c02ac60091108c491dafb00877093170John Hoford                if (t == -1) {
702abb7d134c02ac60091108c491dafb00877093170John Hoford                    mTotalDuration = -1;
703abb7d134c02ac60091108c491dafb00877093170John Hoford                    return -1;
704abb7d134c02ac60091108c491dafb00877093170John Hoford                }
705abb7d134c02ac60091108c491dafb00877093170John Hoford                mTotalDuration = Math.max(mTotalDuration, t);
706abb7d134c02ac60091108c491dafb00877093170John Hoford            }
707abb7d134c02ac60091108c491dafb00877093170John Hoford
708abb7d134c02ac60091108c491dafb00877093170John Hoford            return mTotalDuration;
709abb7d134c02ac60091108c491dafb00877093170John Hoford        }
710abb7d134c02ac60091108c491dafb00877093170John Hoford
711abb7d134c02ac60091108c491dafb00877093170John Hoford        public float getValue() {
712abb7d134c02ac60091108c491dafb00877093170John Hoford            return mAnimationValue;
713abb7d134c02ac60091108c491dafb00877093170John Hoford        }
714abb7d134c02ac60091108c491dafb00877093170John Hoford
715abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
716abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param value the point along the animations to show typically between 0.0f and 1.0f
717abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return true if you need to keep repeating
718abb7d134c02ac60091108c491dafb00877093170John Hoford         */
719abb7d134c02ac60091108c491dafb00877093170John Hoford        public boolean setAnimationFraction(float value) {
720abb7d134c02ac60091108c491dafb00877093170John Hoford            getTotalAnimationDuration();
7219453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
722abb7d134c02ac60091108c491dafb00877093170John Hoford            long animationTime = (long) (value * mTotalDuration);
723abb7d134c02ac60091108c491dafb00877093170John Hoford
7249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int len = mCurrentPaths.length;
725abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < len; i++) {
726abb7d134c02ac60091108c491dafb00877093170John Hoford                animationTime =
727abb7d134c02ac60091108c491dafb00877093170John Hoford                        (long) ((mTotalDuration == -1) ? value * 1000 : mTotalDuration * value);
7289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7299453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final VPath path = mCurrentPaths[i];
7309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final int size = mCurrentAnimList.size();
731abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int j = 0; j < size; j++) {
7329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final VAnimation vAnimation = mCurrentAnimList.get(j);
733abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (vAnimation.doesAdjustPath(path)) {
734abb7d134c02ac60091108c491dafb00877093170John Hoford                        mCurrentPaths[i] =  vAnimation.getPathAtTime(animationTime, path);
735abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
736abb7d134c02ac60091108c491dafb00877093170John Hoford                }
737abb7d134c02ac60091108c491dafb00877093170John Hoford            }
7389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            mAnimationValue = value;
7409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
741abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mTotalDuration == -1) {
742abb7d134c02ac60091108c491dafb00877093170John Hoford                return true;
743abb7d134c02ac60091108c491dafb00877093170John Hoford            } else {
744abb7d134c02ac60091108c491dafb00877093170John Hoford                return animationTime < mTotalDuration;
745abb7d134c02ac60091108c491dafb00877093170John Hoford            }
746abb7d134c02ac60091108c491dafb00877093170John Hoford        }
747abb7d134c02ac60091108c491dafb00877093170John Hoford
7484b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        public void draw(Canvas canvas, int w, int h) {
749abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mCurrentPaths == null) {
750abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.e(LOGTAG,"mCurrentPaths == null");
751abb7d134c02ac60091108c491dafb00877093170John Hoford                return;
752abb7d134c02ac60091108c491dafb00877093170John Hoford            }
753abb7d134c02ac60091108c491dafb00877093170John Hoford
754abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mCurrentPaths.length; i++) {
755abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mCurrentPaths[i] != null && mCurrentPaths[i].isVisible(mCurrentState)) {
756abb7d134c02ac60091108c491dafb00877093170John Hoford                    drawPath(mCurrentPaths[i], canvas, w, h);
757abb7d134c02ac60091108c491dafb00877093170John Hoford                }
758abb7d134c02ac60091108c491dafb00877093170John Hoford            }
759abb7d134c02ac60091108c491dafb00877093170John Hoford        }
760abb7d134c02ac60091108c491dafb00877093170John Hoford
761abb7d134c02ac60091108c491dafb00877093170John Hoford        private void drawPath(VPath vPath, Canvas canvas, int w, int h) {
7629453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final float scale = Math.min(h / mViewportHeight, w / mViewportWidth);
763abb7d134c02ac60091108c491dafb00877093170John Hoford
764abb7d134c02ac60091108c491dafb00877093170John Hoford            vPath.toPath(mPath);
7654b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final Path path = mPath;
766abb7d134c02ac60091108c491dafb00877093170John Hoford
767abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mTrimPathStart != 0.0f || vPath.mTrimPathEnd != 1.0f) {
768abb7d134c02ac60091108c491dafb00877093170John Hoford                float start = (vPath.mTrimPathStart + vPath.mTrimPathOffset) % 1.0f;
769abb7d134c02ac60091108c491dafb00877093170John Hoford                float end = (vPath.mTrimPathEnd + vPath.mTrimPathOffset) % 1.0f;
770abb7d134c02ac60091108c491dafb00877093170John Hoford
771abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPathMeasure == null) {
772abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure = new PathMeasure();
773abb7d134c02ac60091108c491dafb00877093170John Hoford                }
774abb7d134c02ac60091108c491dafb00877093170John Hoford                mPathMeasure.setPath(mPath, false);
775abb7d134c02ac60091108c491dafb00877093170John Hoford
776abb7d134c02ac60091108c491dafb00877093170John Hoford                float len = mPathMeasure.getLength();
777abb7d134c02ac60091108c491dafb00877093170John Hoford                start = start * len;
778abb7d134c02ac60091108c491dafb00877093170John Hoford                end = end * len;
779abb7d134c02ac60091108c491dafb00877093170John Hoford                path.reset();
780abb7d134c02ac60091108c491dafb00877093170John Hoford                if (start > end) {
781abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure.getSegment(start, len, path, true);
782abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure.getSegment(0f, end, path, true);
783abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
784abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure.getSegment(start, end, path, true);
785abb7d134c02ac60091108c491dafb00877093170John Hoford                }
786abb7d134c02ac60091108c491dafb00877093170John Hoford                path.rLineTo(0, 0); // fix bug in measure
787abb7d134c02ac60091108c491dafb00877093170John Hoford            }
788abb7d134c02ac60091108c491dafb00877093170John Hoford
789abb7d134c02ac60091108c491dafb00877093170John Hoford            mRenderPath.reset();
790abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.reset();
791abb7d134c02ac60091108c491dafb00877093170John Hoford
792abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.postRotate(vPath.mRotate, vPath.mPivotX, vPath.mPivotY);
793abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.postScale(scale, scale, mViewportWidth / 2f, mViewportHeight / 2f);
794abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.postTranslate(w / 2f - mViewportWidth / 2f, h / 2f - mViewportHeight / 2f);
795abb7d134c02ac60091108c491dafb00877093170John Hoford
796abb7d134c02ac60091108c491dafb00877093170John Hoford            mRenderPath.addPath(path, mMatrix);
797abb7d134c02ac60091108c491dafb00877093170John Hoford
798abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mClip) {
799abb7d134c02ac60091108c491dafb00877093170John Hoford                canvas.clipPath(mRenderPath, Region.Op.REPLACE);
800abb7d134c02ac60091108c491dafb00877093170John Hoford            }
8019453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
802abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mFillColor != 0) {
8034b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                if (mFillPaint == null) {
8044b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mFillPaint = new Paint();
8054b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mFillPaint.setStyle(Paint.Style.FILL);
8064b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mFillPaint.setAntiAlias(true);
8074b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                }
8084b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
809abb7d134c02ac60091108c491dafb00877093170John Hoford                mFillPaint.setColor(vPath.mFillColor);
810abb7d134c02ac60091108c491dafb00877093170John Hoford                canvas.drawPath(mRenderPath, mFillPaint);
811abb7d134c02ac60091108c491dafb00877093170John Hoford            }
8129453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
813abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mStrokeColor != 0) {
8144b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                if (mStrokePaint == null) {
8154b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mStrokePaint = new Paint();
8164b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mStrokePaint.setStyle(Paint.Style.STROKE);
8174b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mStrokePaint.setAntiAlias(true);
8184b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                }
8194b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
8204b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                final Paint strokePaint = mStrokePaint;
8217f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                if (vPath.mStrokeLineJoin != null) {
8224b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    strokePaint.setStrokeJoin(vPath.mStrokeLineJoin);
823abb7d134c02ac60091108c491dafb00877093170John Hoford                }
8244b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
8257f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                if (vPath.mStrokeLineCap != null) {
8264b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    strokePaint.setStrokeCap(vPath.mStrokeLineCap);
827abb7d134c02ac60091108c491dafb00877093170John Hoford                }
8284b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
8294b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                strokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale);
8304b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                strokePaint.setColor(vPath.mStrokeColor);
8314b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                strokePaint.setStrokeWidth(vPath.mStrokeWidth * scale);
8324b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                canvas.drawPath(mRenderPath, strokePaint);
833abb7d134c02ac60091108c491dafb00877093170John Hoford            }
834abb7d134c02ac60091108c491dafb00877093170John Hoford        }
835abb7d134c02ac60091108c491dafb00877093170John Hoford
836abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
837abb7d134c02ac60091108c491dafb00877093170John Hoford         * Ensure there is at least one animation for every path in group (linking them by names)
838abb7d134c02ac60091108c491dafb00877093170John Hoford         * Build the "current" path based on the first group
839abb7d134c02ac60091108c491dafb00877093170John Hoford         * TODO: improve memory use & performance or move to C++
840abb7d134c02ac60091108c491dafb00877093170John Hoford         */
841abb7d134c02ac60091108c491dafb00877093170John Hoford        public void parseFinish() {
8429453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final HashMap<String, VAnimation> newAnimations = new HashMap<String, VAnimation>();
843abb7d134c02ac60091108c491dafb00877093170John Hoford            for (VGroup group : mGroupList) {
844abb7d134c02ac60091108c491dafb00877093170John Hoford                for (VPath vPath : group.getPaths()) {
845abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (!vPath.mAnimated) {
846abb7d134c02ac60091108c491dafb00877093170John Hoford                        VAnimation ap = null;
847abb7d134c02ac60091108c491dafb00877093170John Hoford
848abb7d134c02ac60091108c491dafb00877093170John Hoford                        if (!newAnimations.containsKey(vPath.getID())) {
849abb7d134c02ac60091108c491dafb00877093170John Hoford                            newAnimations.put(vPath.getID(), ap = new VAnimation());
850abb7d134c02ac60091108c491dafb00877093170John Hoford                        } else {
851abb7d134c02ac60091108c491dafb00877093170John Hoford                            ap = newAnimations.get(vPath.getID());
852abb7d134c02ac60091108c491dafb00877093170John Hoford                        }
8539453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
854abb7d134c02ac60091108c491dafb00877093170John Hoford                        ap.addPath(vPath);
855abb7d134c02ac60091108c491dafb00877093170John Hoford                        vPath.mAnimated = true;
856abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
857abb7d134c02ac60091108c491dafb00877093170John Hoford                }
858abb7d134c02ac60091108c491dafb00877093170John Hoford            }
8599453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
860abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mCurrentAnimList == null) {
861abb7d134c02ac60091108c491dafb00877093170John Hoford                mCurrentAnimList = new ArrayList<VectorDrawable.VAnimation>();
862abb7d134c02ac60091108c491dafb00877093170John Hoford            }
863abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentAnimList.addAll(newAnimations.values());
8649453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
8659453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final Collection<VPath> paths = mGroupList.get(0).getPaths();
866abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentPaths = paths.toArray(new VPath[paths.size()]);
867abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mCurrentPaths.length; i++) {
868abb7d134c02ac60091108c491dafb00877093170John Hoford                mCurrentPaths[i] = new VPath(mCurrentPaths[i]);
869abb7d134c02ac60091108c491dafb00877093170John Hoford            }
870abb7d134c02ac60091108c491dafb00877093170John Hoford        }
871abb7d134c02ac60091108c491dafb00877093170John Hoford
872abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setState(int[] state) {
873abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentState = Arrays.copyOf(state, state.length);
874abb7d134c02ac60091108c491dafb00877093170John Hoford        }
875abb7d134c02ac60091108c491dafb00877093170John Hoford
876abb7d134c02ac60091108c491dafb00877093170John Hoford        int getTrigger(int []state){
877abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mTrigger == 0) return 0;
878abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < state.length; i++) {
879abb7d134c02ac60091108c491dafb00877093170John Hoford                if (state[i] == mTrigger){
880abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (mTriggerState)
881abb7d134c02ac60091108c491dafb00877093170John Hoford                        return 0;
882abb7d134c02ac60091108c491dafb00877093170John Hoford                    mTriggerState = true;
883abb7d134c02ac60091108c491dafb00877093170John Hoford                    return 1;
884abb7d134c02ac60091108c491dafb00877093170John Hoford                }
885abb7d134c02ac60091108c491dafb00877093170John Hoford            }
886abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mTriggerState) {
887abb7d134c02ac60091108c491dafb00877093170John Hoford                mTriggerState = false;
888abb7d134c02ac60091108c491dafb00877093170John Hoford                return -1;
889abb7d134c02ac60091108c491dafb00877093170John Hoford            }
890abb7d134c02ac60091108c491dafb00877093170John Hoford            return 0;
891abb7d134c02ac60091108c491dafb00877093170John Hoford        }
892abb7d134c02ac60091108c491dafb00877093170John Hoford
893abb7d134c02ac60091108c491dafb00877093170John Hoford        public void addAnimation(VAnimation anim) {
894abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mCurrentAnimList == null) {
895abb7d134c02ac60091108c491dafb00877093170John Hoford                mCurrentAnimList = new ArrayList<VectorDrawable.VAnimation>();
896abb7d134c02ac60091108c491dafb00877093170John Hoford            }
897abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentAnimList.add(anim);
898abb7d134c02ac60091108c491dafb00877093170John Hoford        }
899abb7d134c02ac60091108c491dafb00877093170John Hoford
900abb7d134c02ac60091108c491dafb00877093170John Hoford        private void parseViewport(Resources r, AttributeSet attrs)
901abb7d134c02ac60091108c491dafb00877093170John Hoford                throws XmlPullParserException {
9024b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport);
903abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportWidth = a.getFloat(R.styleable.VectorDrawableViewport_viewportWidth, 0);
904abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportHeight = a.getFloat(R.styleable.VectorDrawableViewport_viewportHeight, 0);
905abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mViewportWidth == 0 || mViewportHeight == 0) {
906abb7d134c02ac60091108c491dafb00877093170John Hoford                throw new XmlPullParserException(a.getPositionDescription()+
907abb7d134c02ac60091108c491dafb00877093170John Hoford                        "<viewport> tag requires viewportWidth & viewportHeight to be set");
908abb7d134c02ac60091108c491dafb00877093170John Hoford            }
909abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
910abb7d134c02ac60091108c491dafb00877093170John Hoford        }
911abb7d134c02ac60091108c491dafb00877093170John Hoford
912abb7d134c02ac60091108c491dafb00877093170John Hoford        private void parseSize(Resources r, AttributeSet attrs)
913abb7d134c02ac60091108c491dafb00877093170John Hoford                throws XmlPullParserException  {
9144b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableSize);
915abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseWidth = a.getDimension(R.styleable.VectorDrawableSize_width, 0);
916abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseHeight = a.getDimension(R.styleable.VectorDrawableSize_height, 0);
917abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mBaseWidth == 0 || mBaseHeight == 0) {
918abb7d134c02ac60091108c491dafb00877093170John Hoford                throw new XmlPullParserException(a.getPositionDescription()+
919abb7d134c02ac60091108c491dafb00877093170John Hoford                        "<size> tag requires width & height to be set");
920abb7d134c02ac60091108c491dafb00877093170John Hoford            }
921abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
922abb7d134c02ac60091108c491dafb00877093170John Hoford        }
9234b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
9244b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private static final int getStateForTrigger(int trigger) {
9254b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            return TRIGGER_MAP[trigger];
9264b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        }
927abb7d134c02ac60091108c491dafb00877093170John Hoford    }
928abb7d134c02ac60091108c491dafb00877093170John Hoford
929abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VAnimation {
9305c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private static final String SEPARATOR = ",";
9319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
9325c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private static final int DIRECTION_FORWARD = 0;
9335c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private static final int DIRECTION_IN_AND_OUT = 1;
934abb7d134c02ac60091108c491dafb00877093170John Hoford
935abb7d134c02ac60091108c491dafb00877093170John Hoford        public enum Style {
936abb7d134c02ac60091108c491dafb00877093170John Hoford            INTERPOLATE, CROSSFADE, WIPE
937abb7d134c02ac60091108c491dafb00877093170John Hoford        }
9389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
9395c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private final HashSet<String> mSeqMap = new HashSet<String>();
9405c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
9415c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private Interpolator mAnimInterpolator = new AccelerateDecelerateInterpolator();
9425c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private VPath[] mPaths = new VPath[0];
9435c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private long[] mDuration = { DEFAULT_DURATION };
9449453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
9459453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private int[] mThemeAttrs;
946abb7d134c02ac60091108c491dafb00877093170John Hoford        private Style mStyle;
947abb7d134c02ac60091108c491dafb00877093170John Hoford        private int mLimitProperty = 0;
948abb7d134c02ac60091108c491dafb00877093170John Hoford        private long mStartOffset;
949abb7d134c02ac60091108c491dafb00877093170John Hoford        private long mRepeat = 1;
950abb7d134c02ac60091108c491dafb00877093170John Hoford        private long mWipeDirection;
9515c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private int mMode = DIRECTION_FORWARD;
952abb7d134c02ac60091108c491dafb00877093170John Hoford        private int mInterpolatorType;
953abb7d134c02ac60091108c491dafb00877093170John Hoford        private String mId;
954abb7d134c02ac60091108c491dafb00877093170John Hoford
955abb7d134c02ac60091108c491dafb00877093170John Hoford        public VAnimation() {
9569453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            // Empty constructor.
957abb7d134c02ac60091108c491dafb00877093170John Hoford        }
958abb7d134c02ac60091108c491dafb00877093170John Hoford
9599453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void inflate(ArrayList<VGroup> groups, Resources r, AttributeSet attrs, Theme theme)
960abb7d134c02ac60091108c491dafb00877093170John Hoford                throws XmlPullParserException {
961abb7d134c02ac60091108c491dafb00877093170John Hoford            String value;
962abb7d134c02ac60091108c491dafb00877093170John Hoford            String[] sp;
963abb7d134c02ac60091108c491dafb00877093170John Hoford            int name;
964abb7d134c02ac60091108c491dafb00877093170John Hoford
9659453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableAnimation);
9665c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            final int[] themeAttrs = a.extractThemeAttrs();
9675c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mThemeAttrs = themeAttrs;
968abb7d134c02ac60091108c491dafb00877093170John Hoford
969abb7d134c02ac60091108c491dafb00877093170John Hoford            value = a.getString(R.styleable.VectorDrawableAnimation_sequence);
970abb7d134c02ac60091108c491dafb00877093170John Hoford            if (value != null) {
9715c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                sp = value.split(SEPARATOR);
9725c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                final VectorDrawable.VPath[] paths = new VectorDrawable.VPath[sp.length];
973abb7d134c02ac60091108c491dafb00877093170John Hoford
974abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int j = 0; j < sp.length; j++) {
975abb7d134c02ac60091108c491dafb00877093170John Hoford                    mSeqMap.add(sp[j].trim());
976abb7d134c02ac60091108c491dafb00877093170John Hoford                    VectorDrawable.VPath path = groups.get(j).get(sp[j]);
977abb7d134c02ac60091108c491dafb00877093170John Hoford                    path.mAnimated = true;
978abb7d134c02ac60091108c491dafb00877093170John Hoford                    paths[j] = path;
979abb7d134c02ac60091108c491dafb00877093170John Hoford                }
9805c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
981abb7d134c02ac60091108c491dafb00877093170John Hoford                setPaths(paths);
982abb7d134c02ac60091108c491dafb00877093170John Hoford            }
983abb7d134c02ac60091108c491dafb00877093170John Hoford
984abb7d134c02ac60091108c491dafb00877093170John Hoford            name = R.styleable.VectorDrawableAnimation_durations;
985abb7d134c02ac60091108c491dafb00877093170John Hoford            value = a.getString(name);
986abb7d134c02ac60091108c491dafb00877093170John Hoford            if (value != null) {
987abb7d134c02ac60091108c491dafb00877093170John Hoford                long totalDuration = 0;
9885c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                sp = value.split(SEPARATOR);
9899453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
9909453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final long[] dur = new long[sp.length];
991abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int j = 0; j < dur.length; j++) {
992abb7d134c02ac60091108c491dafb00877093170John Hoford                    dur[j] = Long.parseLong(sp[j]);
993abb7d134c02ac60091108c491dafb00877093170John Hoford                    totalDuration +=  dur[j];
994abb7d134c02ac60091108c491dafb00877093170John Hoford                }
9959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
996abb7d134c02ac60091108c491dafb00877093170John Hoford                if (totalDuration == 0){
9975c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                    throw new XmlPullParserException(a.getPositionDescription()
9985c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                            + " total duration must not be zero");
999abb7d134c02ac60091108c491dafb00877093170John Hoford                }
10009453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1001abb7d134c02ac60091108c491dafb00877093170John Hoford                setDuration(dur);
1002abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1003abb7d134c02ac60091108c491dafb00877093170John Hoford
10045c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            setLimitProperty(a.getInt(R.styleable.VectorDrawableAnimation_limitTo, 0));
1005abb7d134c02ac60091108c491dafb00877093170John Hoford            setRepeat(a.getInt(R.styleable.VectorDrawableAnimation_repeatCount, 1));
1006abb7d134c02ac60091108c491dafb00877093170John Hoford            setStartOffset(a.getInt(R.styleable.VectorDrawableAnimation_startDelay, 0));
1007abb7d134c02ac60091108c491dafb00877093170John Hoford            setMode(a.getInt(R.styleable.VectorDrawableAnimation_repeatStyle, 0));
1008abb7d134c02ac60091108c491dafb00877093170John Hoford
1009abb7d134c02ac60091108c491dafb00877093170John Hoford            fixMissingParameters();
10109453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1011abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
1012abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1013abb7d134c02ac60091108c491dafb00877093170John Hoford
10149453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean canApplyTheme() {
10159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return mThemeAttrs != null;
10169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
10179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
10189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void applyTheme(Theme t) {
10199453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            // TODO: Apply theme.
10209453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
10219453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
10229453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean doesAdjustPath(VPath path) {
10239453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return mSeqMap.contains(path.getID());
10249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
10259453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1026abb7d134c02ac60091108c491dafb00877093170John Hoford        public String getId() {
1027abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mId == null) {
1028abb7d134c02ac60091108c491dafb00877093170John Hoford                mId = mPaths[0].getID();
1029abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int i = 1; i < mPaths.length; i++) {
1030abb7d134c02ac60091108c491dafb00877093170John Hoford                    mId += mPaths[i].getID();
1031abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1032abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1033abb7d134c02ac60091108c491dafb00877093170John Hoford            return mId;
1034abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1035abb7d134c02ac60091108c491dafb00877093170John Hoford
1036abb7d134c02ac60091108c491dafb00877093170John Hoford        public String getPathName() {
1037abb7d134c02ac60091108c491dafb00877093170John Hoford            return mPaths[0].getID();
1038abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1039abb7d134c02ac60091108c491dafb00877093170John Hoford
1040abb7d134c02ac60091108c491dafb00877093170John Hoford        public Style getStyle() {
1041abb7d134c02ac60091108c491dafb00877093170John Hoford            return mStyle;
1042abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1043abb7d134c02ac60091108c491dafb00877093170John Hoford
1044abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setStyle(Style style) {
10455c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mStyle = style;
1046abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1047abb7d134c02ac60091108c491dafb00877093170John Hoford
1048abb7d134c02ac60091108c491dafb00877093170John Hoford        public int getLimitProperty() {
1049abb7d134c02ac60091108c491dafb00877093170John Hoford            return mLimitProperty;
1050abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1051abb7d134c02ac60091108c491dafb00877093170John Hoford
1052abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setLimitProperty(int limitProperty) {
10535c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mLimitProperty = limitProperty;
1054abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1055abb7d134c02ac60091108c491dafb00877093170John Hoford
1056abb7d134c02ac60091108c491dafb00877093170John Hoford        public long[] getDuration() {
1057abb7d134c02ac60091108c491dafb00877093170John Hoford            return mDuration;
1058abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1059abb7d134c02ac60091108c491dafb00877093170John Hoford
1060abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setDuration(long[] duration) {
10615c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mDuration = duration;
1062abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1063abb7d134c02ac60091108c491dafb00877093170John Hoford
1064abb7d134c02ac60091108c491dafb00877093170John Hoford        public long getRepeat() {
1065abb7d134c02ac60091108c491dafb00877093170John Hoford            return mRepeat;
1066abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1067abb7d134c02ac60091108c491dafb00877093170John Hoford
1068abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setRepeat(long repeat) {
10695c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mRepeat = repeat;
1070abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1071abb7d134c02ac60091108c491dafb00877093170John Hoford
1072abb7d134c02ac60091108c491dafb00877093170John Hoford        public long getStartOffset() {
1073abb7d134c02ac60091108c491dafb00877093170John Hoford            return mStartOffset;
1074abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1075abb7d134c02ac60091108c491dafb00877093170John Hoford
1076abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setStartOffset(long startOffset) {
10775c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mStartOffset = startOffset;
1078abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1079abb7d134c02ac60091108c491dafb00877093170John Hoford
1080abb7d134c02ac60091108c491dafb00877093170John Hoford        public long getWipeDirection() {
1081abb7d134c02ac60091108c491dafb00877093170John Hoford            return mWipeDirection;
1082abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1083abb7d134c02ac60091108c491dafb00877093170John Hoford
1084abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setWipeDirection(long wipeDirection) {
10855c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mWipeDirection = wipeDirection;
1086abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1087abb7d134c02ac60091108c491dafb00877093170John Hoford
1088abb7d134c02ac60091108c491dafb00877093170John Hoford        public int getMode() {
1089abb7d134c02ac60091108c491dafb00877093170John Hoford            return mMode;
1090abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1091abb7d134c02ac60091108c491dafb00877093170John Hoford
1092abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setMode(int mode) {
10935c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mMode = mode;
1094abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1095abb7d134c02ac60091108c491dafb00877093170John Hoford
1096abb7d134c02ac60091108c491dafb00877093170John Hoford        public int getInterpolator() {
1097abb7d134c02ac60091108c491dafb00877093170John Hoford            return mInterpolatorType;
1098abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1099abb7d134c02ac60091108c491dafb00877093170John Hoford
1100abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setInterpolator(int interpolator) {
11015c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mInterpolatorType = interpolator;
1102abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1103abb7d134c02ac60091108c491dafb00877093170John Hoford
1104abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1105abb7d134c02ac60091108c491dafb00877093170John Hoford         * compute the total time in milliseconds
1106abb7d134c02ac60091108c491dafb00877093170John Hoford         *
1107abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return the total time in milliseconds the animation will take
1108abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1109abb7d134c02ac60091108c491dafb00877093170John Hoford        public long getTotalDuration() {
1110abb7d134c02ac60091108c491dafb00877093170John Hoford            long total = mStartOffset;
1111abb7d134c02ac60091108c491dafb00877093170John Hoford            if (getRepeat() == -1) {
1112abb7d134c02ac60091108c491dafb00877093170John Hoford                return -1;
1113abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1114abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mDuration.length; i++) {
1115abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mRepeat > 1) {
1116abb7d134c02ac60091108c491dafb00877093170John Hoford                    total += mDuration[i] * mRepeat;
1117abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
1118abb7d134c02ac60091108c491dafb00877093170John Hoford                    total += mDuration[i];
1119abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1120abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1121abb7d134c02ac60091108c491dafb00877093170John Hoford            return total;
1122abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1123abb7d134c02ac60091108c491dafb00877093170John Hoford
1124abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setPaths(VPath[] paths) {
11259453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            mPaths = paths;
1126abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1127abb7d134c02ac60091108c491dafb00877093170John Hoford
1128abb7d134c02ac60091108c491dafb00877093170John Hoford        public void addPath(VPath path) {
1129abb7d134c02ac60091108c491dafb00877093170John Hoford            mPaths = Arrays.copyOf(mPaths, mPaths.length + 1);
1130abb7d134c02ac60091108c491dafb00877093170John Hoford            mPaths[mPaths.length - 1] = path;
1131abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1132abb7d134c02ac60091108c491dafb00877093170John Hoford
1133abb7d134c02ac60091108c491dafb00877093170John Hoford        public boolean containsPath(String pathid) {
1134abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mPaths.length; i++) {
1135abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPaths[i].getID().equals(pathid)) {
1136abb7d134c02ac60091108c491dafb00877093170John Hoford                    return true;
1137abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1138abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1139abb7d134c02ac60091108c491dafb00877093170John Hoford            return false;
1140abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1141abb7d134c02ac60091108c491dafb00877093170John Hoford
1142abb7d134c02ac60091108c491dafb00877093170John Hoford        public void interpolate(VPath p1, VPath p2, float time, VPath dest) {
11439453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            VPath.interpolate(time, p1, p2, dest, mLimitProperty);
1144abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1145abb7d134c02ac60091108c491dafb00877093170John Hoford
1146abb7d134c02ac60091108c491dafb00877093170John Hoford        public VPath getPathAtTime(long milliseconds, VPath dest) {
1147abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mPaths.length == 1) {
1148abb7d134c02ac60091108c491dafb00877093170John Hoford                dest.copyFrom(mPaths[0]);
1149abb7d134c02ac60091108c491dafb00877093170John Hoford                return dest;
1150abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1151abb7d134c02ac60091108c491dafb00877093170John Hoford            long point = milliseconds - mStartOffset;
1152abb7d134c02ac60091108c491dafb00877093170John Hoford            if (point < 0) {
1153abb7d134c02ac60091108c491dafb00877093170John Hoford                point = 0;
1154abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1155abb7d134c02ac60091108c491dafb00877093170John Hoford            float time = 0;
1156abb7d134c02ac60091108c491dafb00877093170John Hoford            long sum = mDuration[0];
1157abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 1; i < mDuration.length; i++) {
1158abb7d134c02ac60091108c491dafb00877093170John Hoford                sum += mDuration[i];
1159abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1160abb7d134c02ac60091108c491dafb00877093170John Hoford
1161abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mRepeat > 1) {
1162abb7d134c02ac60091108c491dafb00877093170John Hoford                time = point / (float) (sum * mRepeat);
1163abb7d134c02ac60091108c491dafb00877093170John Hoford                time = mAnimInterpolator.getInterpolation(time);
1164abb7d134c02ac60091108c491dafb00877093170John Hoford
1165abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mMode == DIRECTION_IN_AND_OUT) {
1166abb7d134c02ac60091108c491dafb00877093170John Hoford                    point = ((long) (time * sum * 2 * mRepeat)) % (sum * 2);
1167abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (point > sum) {
1168abb7d134c02ac60091108c491dafb00877093170John Hoford                        point = sum * 2 - point;
1169abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1170abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
1171abb7d134c02ac60091108c491dafb00877093170John Hoford                    point = ((long) (time * sum * mRepeat)) % sum;
1172abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1173abb7d134c02ac60091108c491dafb00877093170John Hoford            } else if (mRepeat == 1) {
1174abb7d134c02ac60091108c491dafb00877093170John Hoford                time = point / (float) (sum * mRepeat);
1175abb7d134c02ac60091108c491dafb00877093170John Hoford                time = mAnimInterpolator.getInterpolation(time);
1176abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mMode == DIRECTION_IN_AND_OUT) {
1177abb7d134c02ac60091108c491dafb00877093170John Hoford                    point = ((long) (time * sum * 2 * mRepeat));
1178abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (point > sum) {
1179abb7d134c02ac60091108c491dafb00877093170John Hoford                        point = sum * 2 - point;
1180abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1181abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
1182abb7d134c02ac60091108c491dafb00877093170John Hoford                    point = Math.min(((long) (time * sum * mRepeat)), sum);
1183abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1184abb7d134c02ac60091108c491dafb00877093170John Hoford
1185abb7d134c02ac60091108c491dafb00877093170John Hoford            } else { // repeat = -1
1186abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mMode == DIRECTION_IN_AND_OUT) {
1187abb7d134c02ac60091108c491dafb00877093170John Hoford                    point = point % (sum * 2);
1188abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (point > sum) {
1189abb7d134c02ac60091108c491dafb00877093170John Hoford                        point = sum * 2 - point;
1190abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1191abb7d134c02ac60091108c491dafb00877093170John Hoford                    time = point / (float) sum;
1192abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
1193abb7d134c02ac60091108c491dafb00877093170John Hoford                    point = point % sum;
1194abb7d134c02ac60091108c491dafb00877093170John Hoford                    time = point / (float) sum;
1195abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1196abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1197abb7d134c02ac60091108c491dafb00877093170John Hoford
1198abb7d134c02ac60091108c491dafb00877093170John Hoford            int transition = 0;
1199abb7d134c02ac60091108c491dafb00877093170John Hoford            while (point > mDuration[transition]) {
1200abb7d134c02ac60091108c491dafb00877093170John Hoford                point -= mDuration[transition++];
1201abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1202abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mPaths.length > (transition + 1)) {
1203abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPaths[transition].getID() != dest.getID()) {
1204abb7d134c02ac60091108c491dafb00877093170John Hoford                    dest.copyFrom(mPaths[transition]);
1205abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1206abb7d134c02ac60091108c491dafb00877093170John Hoford                interpolate(mPaths[transition], mPaths[transition + 1],
1207abb7d134c02ac60091108c491dafb00877093170John Hoford                        point / (float) mDuration[transition], dest);
1208abb7d134c02ac60091108c491dafb00877093170John Hoford            } else {
1209abb7d134c02ac60091108c491dafb00877093170John Hoford                interpolate(mPaths[transition], mPaths[transition], 0, dest);
1210abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1211abb7d134c02ac60091108c491dafb00877093170John Hoford            return dest;
1212abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1213abb7d134c02ac60091108c491dafb00877093170John Hoford
1214abb7d134c02ac60091108c491dafb00877093170John Hoford        void fixMissingParameters() {
1215abb7d134c02ac60091108c491dafb00877093170John Hoford            // fix missing points
1216abb7d134c02ac60091108c491dafb00877093170John Hoford            float rotation = Float.NaN;
1217abb7d134c02ac60091108c491dafb00877093170John Hoford            float rotationY = Float.NaN;
1218abb7d134c02ac60091108c491dafb00877093170John Hoford            float rotationX = Float.NaN;
1219abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mPaths.length; i++) {
1220abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPaths[i].mPivotX > 0) {
1221abb7d134c02ac60091108c491dafb00877093170John Hoford                    rotationX = mPaths[i].mPivotX;
1222abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1223abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPaths[i].mPivotY > 0) {
1224abb7d134c02ac60091108c491dafb00877093170John Hoford                    rotationY = mPaths[i].mPivotY;
1225abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1226abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPaths[i].mRotate > 0) {
1227abb7d134c02ac60091108c491dafb00877093170John Hoford                    rotation = mPaths[i].mRotate;
1228abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1229abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1230abb7d134c02ac60091108c491dafb00877093170John Hoford            if (rotation > 0) {
1231abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int i = 0; i < mPaths.length; i++) {
1232abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (mPaths[i].mPivotX == 0) {
1233abb7d134c02ac60091108c491dafb00877093170John Hoford                        mPaths[i].mPivotX = rotationX;
1234abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1235abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (mPaths[i].mPivotY == 0) {
1236abb7d134c02ac60091108c491dafb00877093170John Hoford                        mPaths[i].mPivotY = rotationY;
1237abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1238abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1239abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1240abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1241abb7d134c02ac60091108c491dafb00877093170John Hoford    }
1242abb7d134c02ac60091108c491dafb00877093170John Hoford
1243abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VGroup {
12449453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private final HashMap<String, VPath> mVGPathMap = new HashMap<String, VPath>();
12459453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private final ArrayList<VPath> mVGList = new ArrayList<VPath>();
1246abb7d134c02ac60091108c491dafb00877093170John Hoford
1247abb7d134c02ac60091108c491dafb00877093170John Hoford        public void add(VPath path) {
1248abb7d134c02ac60091108c491dafb00877093170John Hoford            String id = path.getID();
1249abb7d134c02ac60091108c491dafb00877093170John Hoford            mVGPathMap.put(id, path);
1250abb7d134c02ac60091108c491dafb00877093170John Hoford            mVGList.add(path);
1251abb7d134c02ac60091108c491dafb00877093170John Hoford         }
1252abb7d134c02ac60091108c491dafb00877093170John Hoford
1253abb7d134c02ac60091108c491dafb00877093170John Hoford        public VPath get(String name) {
1254abb7d134c02ac60091108c491dafb00877093170John Hoford            return mVGPathMap.get(name);
1255abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1256abb7d134c02ac60091108c491dafb00877093170John Hoford
1257abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1258abb7d134c02ac60091108c491dafb00877093170John Hoford         * Must return in order of adding
1259abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return ordered list of paths
1260abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1261abb7d134c02ac60091108c491dafb00877093170John Hoford        public Collection<VPath> getPaths() {
1262abb7d134c02ac60091108c491dafb00877093170John Hoford            return mVGList;
1263abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1264abb7d134c02ac60091108c491dafb00877093170John Hoford
1265abb7d134c02ac60091108c491dafb00877093170John Hoford        public int size() {
1266abb7d134c02ac60091108c491dafb00877093170John Hoford            return mVGPathMap.size();
1267abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1268abb7d134c02ac60091108c491dafb00877093170John Hoford    }
1269abb7d134c02ac60091108c491dafb00877093170John Hoford
1270abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VPath {
1271abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int LIMIT_ALL = 0;
1272abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int LIMIT_PATH = 1;
1273abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int LIMIT_ROTATE = 2;
1274abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int LIMIT_TRIM_PATH_START = 3;
1275abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int LIMIT_TRIM_PATH_OFFSET = 5;
1276abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int LIMIT_TRIM_PATH_END = 4;
12779453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1278abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int STATE_UNDEFINED=0;
1279abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int STATE_TRUE=1;
1280abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int STATE_FALSE=2;
12819453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1282abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int MAX_STATES = 10;
12839453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
12849453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private int[] mThemeAttrs;
12859453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1286abb7d134c02ac60091108c491dafb00877093170John Hoford        int mStrokeColor = 0;
1287abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeWidth = 0;
1288abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeOpacity = Float.NaN;
12899453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1290abb7d134c02ac60091108c491dafb00877093170John Hoford        int mFillColor = 0;
1291abb7d134c02ac60091108c491dafb00877093170John Hoford        int mFillRule;
1292abb7d134c02ac60091108c491dafb00877093170John Hoford        float mFillOpacity = Float.NaN;
12939453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1294abb7d134c02ac60091108c491dafb00877093170John Hoford        float mRotate = 0;
1295abb7d134c02ac60091108c491dafb00877093170John Hoford        float mPivotX = 0;
1296abb7d134c02ac60091108c491dafb00877093170John Hoford        float mPivotY = 0;
12979453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1298abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathStart = 0;
1299abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathEnd = 1;
1300abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathOffset = 0;
13019453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1302abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean mAnimated = false;
1303abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean mClip = false;
13044b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        Paint.Cap mStrokeLineCap = Paint.Cap.BUTT;
13054b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        Paint.Join mStrokeLineJoin = Paint.Join.MITER;
1306abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeMiterlimit = 4;
13079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
13089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private VNode[] mNode = null;
13099453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private String mId;
1310abb7d134c02ac60091108c491dafb00877093170John Hoford        private int[] mCheckState = new int[MAX_STATES];
1311abb7d134c02ac60091108c491dafb00877093170John Hoford        private boolean[] mCheckValue = new boolean[MAX_STATES];
1312abb7d134c02ac60091108c491dafb00877093170John Hoford        private int mNumberOfStates = 0;
1313abb7d134c02ac60091108c491dafb00877093170John Hoford        private int mNumberOfTrue = 0;
1314abb7d134c02ac60091108c491dafb00877093170John Hoford
13159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public VPath() {
13169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            // Empty constructor.
13179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
13189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
13199453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public VPath(VPath p) {
13209453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            copyFrom(p);
13219453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
13229453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1323abb7d134c02ac60091108c491dafb00877093170John Hoford        public void addStateFilter(int state, boolean condition) {
1324abb7d134c02ac60091108c491dafb00877093170John Hoford            int k = 0;
1325abb7d134c02ac60091108c491dafb00877093170John Hoford            while (k < mNumberOfStates) {
1326abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mCheckState[mNumberOfStates] == state)
1327abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1328abb7d134c02ac60091108c491dafb00877093170John Hoford                k++;
1329abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1330abb7d134c02ac60091108c491dafb00877093170John Hoford            mCheckState[k] = state;
1331abb7d134c02ac60091108c491dafb00877093170John Hoford            mCheckValue[k] = condition;
1332abb7d134c02ac60091108c491dafb00877093170John Hoford            if (k==mNumberOfStates){
1333abb7d134c02ac60091108c491dafb00877093170John Hoford                mNumberOfStates++;
1334abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1335abb7d134c02ac60091108c491dafb00877093170John Hoford            if (condition) {
1336abb7d134c02ac60091108c491dafb00877093170John Hoford                mNumberOfTrue++;
1337abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1338abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1339abb7d134c02ac60091108c491dafb00877093170John Hoford
13409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private int getState(int state){
1341abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mNumberOfStates; i++) {
1342abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mCheckState[mNumberOfStates] == state){
1343abb7d134c02ac60091108c491dafb00877093170John Hoford                    return (mCheckValue[i])?STATE_TRUE:STATE_FALSE;
1344abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1345abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1346abb7d134c02ac60091108c491dafb00877093170John Hoford            return STATE_UNDEFINED;
1347abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1348abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1349abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return the name of the path
1350abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1351abb7d134c02ac60091108c491dafb00877093170John Hoford        public String getName() {
1352abb7d134c02ac60091108c491dafb00877093170John Hoford            return mId;
1353abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1354abb7d134c02ac60091108c491dafb00877093170John Hoford
1355abb7d134c02ac60091108c491dafb00877093170John Hoford        public void toPath(Path path) {
1356abb7d134c02ac60091108c491dafb00877093170John Hoford            path.reset();
1357abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mNode != null) {
1358abb7d134c02ac60091108c491dafb00877093170John Hoford                VNode.createPath(mNode, path);
1359abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1360abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1361abb7d134c02ac60091108c491dafb00877093170John Hoford
13627f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        public String getID() {
1363abb7d134c02ac60091108c491dafb00877093170John Hoford            return mId;
1364abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1365abb7d134c02ac60091108c491dafb00877093170John Hoford
13667f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) {
13677f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            switch (id) {
13687f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_BUTT:
13697f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.BUTT;
13707f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_ROUND:
13717f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.ROUND;
13727f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_SQUARE:
13737f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.SQUARE;
13747f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                default:
13757f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return defValue;
13767f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
13777f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        }
13787f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
13797f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        private Paint.Join getStrokeLineJoin(int id, Paint.Join defValue) {
13807f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            switch (id) {
13817f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_MITER:
13827f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.MITER;
13837f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_ROUND:
13847f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.ROUND;
13857f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_BEVEL:
13867f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.BEVEL;
13877f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                default:
13887f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return defValue;
13897f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
13907f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        }
13917f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
13929453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void inflate(Resources r, AttributeSet attrs, Theme theme) {
13939453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawablePath);
13949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int[] themeAttrs = a.extractThemeAttrs();
13959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            mThemeAttrs = themeAttrs;
13969453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
13977f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            // NOTE: The set of attributes loaded here MUST match the
13987f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            // set of attributes loaded in applyTheme.
13997f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_clipToPath] == 0) {
14007f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
14017f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14027f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
14037f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_name] == 0) {
14047f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mId = a.getString(R.styleable.VectorDrawablePath_name);
14057f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14067f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
14077f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pathData] == 0) {
14087f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData));
14097f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
1410abb7d134c02ac60091108c491dafb00877093170John Hoford
14119453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fill] == 0) {
14127f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor);
14139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
14149453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14157f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fillOpacity] == 0) {
14167f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity);
1417abb7d134c02ac60091108c491dafb00877093170John Hoford            }
14189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14197f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_rotation] == 0) {
14207f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mRotate = a.getFloat(R.styleable.VectorDrawablePath_rotation, mRotate);
14217f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14229453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14237f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pivotX] == 0) {
14247f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mPivotX = a.getFloat(R.styleable.VectorDrawablePath_pivotX, mPivotX);
1425abb7d134c02ac60091108c491dafb00877093170John Hoford            }
14269453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14277f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pivotY] == 0) {
14287f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mPivotY = a.getFloat(R.styleable.VectorDrawablePath_pivotY, mPivotY);
14297f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14307f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
14317f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
14327f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeLineCap] == 0) {
14337f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeLineCap = getStrokeLineCap(
14347f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        a.getInt(R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
14357f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14367f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
14377f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
14387f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeLineJoin] == 0) {
14397f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeLineJoin = getStrokeLineJoin(
14407f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        a.getInt(R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
1441abb7d134c02ac60091108c491dafb00877093170John Hoford            }
14429453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14437f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
14447f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeMiterLimit] == 0) {
14457f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeMiterlimit = a.getFloat(
14467f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
14477f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14489453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14499453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_stroke] == 0) {
14509453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor);
1451abb7d134c02ac60091108c491dafb00877093170John Hoford            }
14529453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14539453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null
14549453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeOpacity] == 0) {
14559453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeOpacity = a.getFloat(
14567f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity);
14579453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
14589453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14597f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_strokeWidth] == 0) {
14607f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth);
14617f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14627f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
14637f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_trimPathEnd] == 0) {
14647f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd);
14657f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14669453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14677f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
14687f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_trimPathOffset] == 0) {
14697f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathOffset = a.getFloat(
14707f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
14717f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14727f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
14737f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
14747f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_trimPathStart] == 0) {
14757f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathStart = a.getFloat(
14767f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
14777f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14787f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
14797f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            // TODO: Consider replacing this with existing state attributes.
14809453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int[] states = {
14819453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    R.styleable.VectorDrawablePath_state_activated,
1482abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_checkable,
1483abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_checked,
1484abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_enabled,
1485abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_focused,
1486abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_hovered,
1487abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_pressed,
1488abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_selected,
14899453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    R.styleable.VectorDrawablePath_state_window_focused
14909453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            };
14919453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14929453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int N = states.length;
14939453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            for (int i = 0; i < N; i++) {
14949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final int state = states[i];
1495abb7d134c02ac60091108c491dafb00877093170John Hoford                if (a.hasValue(state)) {
1496abb7d134c02ac60091108c491dafb00877093170John Hoford                    addStateFilter(state, a.getBoolean(state, false));
1497abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1498abb7d134c02ac60091108c491dafb00877093170John Hoford            }
14999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15009453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            updateColorAlphas();
15019453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1502abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
1503abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1504abb7d134c02ac60091108c491dafb00877093170John Hoford
15059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean canApplyTheme() {
15069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return mThemeAttrs != null;
15079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
15089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15099453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void applyTheme(Theme t) {
15109453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (mThemeAttrs == null) {
15119453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                return;
15129453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
15139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15149453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final TypedArray a = t.resolveAttributes(
15159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    mThemeAttrs, R.styleable.VectorDrawablePath, 0, 0);
15169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15177f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
15189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15197f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (a.hasValue(R.styleable.VectorDrawablePath_name)) {
15207f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mId = a.getString(R.styleable.VectorDrawablePath_name);
15219453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
15229453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15237f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (a.hasValue(R.styleable.VectorDrawablePath_pathData)) {
15247f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData));
15259453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
15269453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15277f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor);
15287f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity);
15297f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
15307f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mRotate = a.getFloat(R.styleable.VectorDrawablePath_rotation, mRotate);
15317f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mPivotX = a.getFloat(R.styleable.VectorDrawablePath_pivotX, mPivotX);
15327f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mPivotY = a.getFloat(R.styleable.VectorDrawablePath_pivotY, mPivotY);
15337f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
15347f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineCap = getStrokeLineCap(a.getInt(
15357f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
15367f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineJoin = getStrokeLineJoin(a.getInt(
15377f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
15387f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeMiterlimit = a.getFloat(
15397f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
15407f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor);
15417f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeOpacity = a.getFloat(
15427f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity);
15437f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth);
15447f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
15457f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd);
15467f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathOffset = a.getFloat(
15477f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
15487f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathStart = a.getFloat(
15497f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
15509453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15519453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            updateColorAlphas();
15529453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
15539453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15549453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private void updateColorAlphas() {
15559453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (!Float.isNaN(mFillOpacity)) {
15569453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mFillColor &= 0x00FFFFFF;
15579453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mFillColor |= ((int) (0xFF * mFillOpacity)) << 24;
15589453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
15599453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15609453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (!Float.isNaN(mStrokeOpacity)) {
15619453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor &= 0x00FFFFFF;
15629453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor |= ((int) (0xFF * mStrokeOpacity)) << 24;
15639453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
15649453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
15659453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1566abb7d134c02ac60091108c491dafb00877093170John Hoford        private static int nextStart(String s, int end) {
1567abb7d134c02ac60091108c491dafb00877093170John Hoford            char c;
1568abb7d134c02ac60091108c491dafb00877093170John Hoford
1569abb7d134c02ac60091108c491dafb00877093170John Hoford            while (end < s.length()) {
1570abb7d134c02ac60091108c491dafb00877093170John Hoford                c = s.charAt(end);
1571abb7d134c02ac60091108c491dafb00877093170John Hoford                if (((c - 'A') * (c - 'Z') <= 0) || (((c - 'a') * (c - 'z') <= 0))) {
1572abb7d134c02ac60091108c491dafb00877093170John Hoford                    return end;
1573abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1574abb7d134c02ac60091108c491dafb00877093170John Hoford                end++;
1575abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1576abb7d134c02ac60091108c491dafb00877093170John Hoford            return end;
1577abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1578abb7d134c02ac60091108c491dafb00877093170John Hoford
1579abb7d134c02ac60091108c491dafb00877093170John Hoford        private void addNode(ArrayList<VectorDrawable.VNode> list, char cmd, float[] val) {
1580abb7d134c02ac60091108c491dafb00877093170John Hoford            list.add(new VectorDrawable.VNode(cmd, val));
1581abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1582abb7d134c02ac60091108c491dafb00877093170John Hoford
1583abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1584abb7d134c02ac60091108c491dafb00877093170John Hoford         * parse the floats in the string
1585abb7d134c02ac60091108c491dafb00877093170John Hoford         * this is an optimized version of
1586abb7d134c02ac60091108c491dafb00877093170John Hoford         * parseFloat(s.split(",|\\s"));
1587abb7d134c02ac60091108c491dafb00877093170John Hoford         *
1588abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param s the string containing a command and list of floats
1589abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return array of floats
1590abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1591abb7d134c02ac60091108c491dafb00877093170John Hoford        private static float[] getFloats(String s) {
1592abb7d134c02ac60091108c491dafb00877093170John Hoford            if (s.charAt(0) == 'z' | s.charAt(0) == 'Z') {
1593abb7d134c02ac60091108c491dafb00877093170John Hoford                return new float[0];
1594abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1595abb7d134c02ac60091108c491dafb00877093170John Hoford            try {
1596abb7d134c02ac60091108c491dafb00877093170John Hoford                float[] tmp = new float[s.length()];
1597abb7d134c02ac60091108c491dafb00877093170John Hoford                int count = 0;
1598abb7d134c02ac60091108c491dafb00877093170John Hoford                int pos = 1, end;
1599abb7d134c02ac60091108c491dafb00877093170John Hoford                while ((end = extract(s, pos)) >= 0) {
1600abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (pos < end) {
1601abb7d134c02ac60091108c491dafb00877093170John Hoford                        tmp[count++] = Float.parseFloat(s.substring(pos, end));
1602abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1603abb7d134c02ac60091108c491dafb00877093170John Hoford                    pos = end + 1;
1604abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1605abb7d134c02ac60091108c491dafb00877093170John Hoford                // handle the final float if there is one
1606abb7d134c02ac60091108c491dafb00877093170John Hoford                if (pos < s.length()) {
1607abb7d134c02ac60091108c491dafb00877093170John Hoford                    tmp[count++] = Float.parseFloat(s.substring(pos, s.length()));
1608abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1609abb7d134c02ac60091108c491dafb00877093170John Hoford                return Arrays.copyOf(tmp, count);
1610abb7d134c02ac60091108c491dafb00877093170John Hoford            } catch (NumberFormatException e){
1611abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.e(LOGTAG,"error in parsing \""+s+"\"");
1612abb7d134c02ac60091108c491dafb00877093170John Hoford                throw e;
1613abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1614abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1615abb7d134c02ac60091108c491dafb00877093170John Hoford
1616abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1617abb7d134c02ac60091108c491dafb00877093170John Hoford         * calculate the position of the next comma or space
1618abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param s the string to search
1619abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param start the position to start searching
1620abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return the position of the next comma or space or -1 if none found
1621abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1622abb7d134c02ac60091108c491dafb00877093170John Hoford        private static int extract(String s, int start) {
1623abb7d134c02ac60091108c491dafb00877093170John Hoford            int space = s.indexOf(' ', start);
1624abb7d134c02ac60091108c491dafb00877093170John Hoford            int comma = s.indexOf(',', start);
1625abb7d134c02ac60091108c491dafb00877093170John Hoford            if (space == -1) {
1626abb7d134c02ac60091108c491dafb00877093170John Hoford                return comma;
1627abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1628abb7d134c02ac60091108c491dafb00877093170John Hoford            if (comma == -1) {
1629abb7d134c02ac60091108c491dafb00877093170John Hoford                return space;
1630abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1631abb7d134c02ac60091108c491dafb00877093170John Hoford            return (comma > space) ? space : comma;
1632abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1633abb7d134c02ac60091108c491dafb00877093170John Hoford
1634abb7d134c02ac60091108c491dafb00877093170John Hoford        private VectorDrawable.VNode[] parsePath(String value) {
1635abb7d134c02ac60091108c491dafb00877093170John Hoford            int start = 0;
1636abb7d134c02ac60091108c491dafb00877093170John Hoford            int end = 1;
1637abb7d134c02ac60091108c491dafb00877093170John Hoford
1638abb7d134c02ac60091108c491dafb00877093170John Hoford            ArrayList<VectorDrawable.VNode> list = new ArrayList<VectorDrawable.VNode>();
1639abb7d134c02ac60091108c491dafb00877093170John Hoford            while (end < value.length()) {
1640abb7d134c02ac60091108c491dafb00877093170John Hoford                end = nextStart(value, end);
1641abb7d134c02ac60091108c491dafb00877093170John Hoford                String s = value.substring(start, end);
1642abb7d134c02ac60091108c491dafb00877093170John Hoford                float[] val = getFloats(s);
1643abb7d134c02ac60091108c491dafb00877093170John Hoford                addNode(list, s.charAt(0), val);
1644abb7d134c02ac60091108c491dafb00877093170John Hoford
1645abb7d134c02ac60091108c491dafb00877093170John Hoford                start = end;
1646abb7d134c02ac60091108c491dafb00877093170John Hoford                end++;
1647abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1648abb7d134c02ac60091108c491dafb00877093170John Hoford            if ((end - start) == 1 && start < value.length()) {
1649abb7d134c02ac60091108c491dafb00877093170John Hoford
1650abb7d134c02ac60091108c491dafb00877093170John Hoford                addNode(list, value.charAt(start), new float[0]);
1651abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1652abb7d134c02ac60091108c491dafb00877093170John Hoford            return list.toArray(new VectorDrawable.VNode[list.size()]);
1653abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1654abb7d134c02ac60091108c491dafb00877093170John Hoford
1655abb7d134c02ac60091108c491dafb00877093170John Hoford        public void copyFrom(VPath p1) {
1656abb7d134c02ac60091108c491dafb00877093170John Hoford            mNode = new VNode[p1.mNode.length];
1657abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mNode.length; i++) {
1658abb7d134c02ac60091108c491dafb00877093170John Hoford                mNode[i] = new VNode(p1.mNode[i]);
1659abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1660abb7d134c02ac60091108c491dafb00877093170John Hoford            mId = p1.mId;
1661abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokeColor = p1.mStrokeColor;
1662abb7d134c02ac60091108c491dafb00877093170John Hoford            mFillColor = p1.mFillColor;
1663abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokeWidth = p1.mStrokeWidth;
1664abb7d134c02ac60091108c491dafb00877093170John Hoford            mRotate = p1.mRotate;
1665abb7d134c02ac60091108c491dafb00877093170John Hoford            mPivotX = p1.mPivotX;
1666abb7d134c02ac60091108c491dafb00877093170John Hoford            mPivotY = p1.mPivotY;
1667abb7d134c02ac60091108c491dafb00877093170John Hoford            mAnimated = p1.mAnimated;
1668abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrimPathStart = p1.mTrimPathStart;
1669abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrimPathEnd = p1.mTrimPathEnd;
1670abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrimPathOffset = p1.mTrimPathOffset;
16717f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineCap = p1.mStrokeLineCap;
16727f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineJoin = p1.mStrokeLineJoin;
1673abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokeMiterlimit = p1.mStrokeMiterlimit;
1674abb7d134c02ac60091108c491dafb00877093170John Hoford            mNumberOfStates = p1.mNumberOfStates;
1675abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mNumberOfStates; i++) {
1676abb7d134c02ac60091108c491dafb00877093170John Hoford                mCheckState[i] = p1.mCheckState[i];
1677abb7d134c02ac60091108c491dafb00877093170John Hoford                mCheckValue[i] = p1.mCheckValue[i];
1678abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1679abb7d134c02ac60091108c491dafb00877093170John Hoford
1680abb7d134c02ac60091108c491dafb00877093170John Hoford            mFillRule = p1.mFillRule;
1681abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1682abb7d134c02ac60091108c491dafb00877093170John Hoford
1683abb7d134c02ac60091108c491dafb00877093170John Hoford        public static VPath interpolate(float t, VPath p1, VPath p2, VPath returnPath, int limit) {
1684abb7d134c02ac60091108c491dafb00877093170John Hoford            if (limit == LIMIT_ALL || limit == LIMIT_PATH) {
1685abb7d134c02ac60091108c491dafb00877093170John Hoford                if (returnPath.mNode == null || returnPath.mNode.length != p1.mNode.length) {
1686abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mNode = new VNode[p1.mNode.length];
1687abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1688abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int i = 0; i < returnPath.mNode.length; i++) {
1689abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (returnPath.mNode[i] == null) {
1690abb7d134c02ac60091108c491dafb00877093170John Hoford                        returnPath.mNode[i] = new VNode(p1.mNode[i], p2.mNode[i], t);
1691abb7d134c02ac60091108c491dafb00877093170John Hoford                    } else {
1692abb7d134c02ac60091108c491dafb00877093170John Hoford                        returnPath.mNode[i].interpolate(p1.mNode[i], p2.mNode[i], t);
1693abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1694abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1695abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1696abb7d134c02ac60091108c491dafb00877093170John Hoford            float t1 = 1 - t;
1697abb7d134c02ac60091108c491dafb00877093170John Hoford            switch (limit) {
1698abb7d134c02ac60091108c491dafb00877093170John Hoford                case LIMIT_ALL:
1699abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mRotate = t1 * p1.mRotate + t * p2.mRotate;
1700abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mPivotX = t1 * p1.mPivotX + t * p2.mPivotX;
1701abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mPivotY = t1 * p1.mPivotY + t * p2.mPivotY;
1702abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mClip = p1.mClip | p2.mClip;
1703abb7d134c02ac60091108c491dafb00877093170John Hoford
1704abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mTrimPathStart = t1 * p1.mTrimPathStart + t * p2.mTrimPathStart;
1705abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mTrimPathEnd = t1 * p1.mTrimPathEnd + t * p2.mTrimPathEnd;
1706abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mTrimPathOffset = t1 * p1.mTrimPathOffset + t * p2.mTrimPathOffset;
1707abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mStrokeMiterlimit =
1708abb7d134c02ac60091108c491dafb00877093170John Hoford                            t1 * p1.mStrokeMiterlimit + t * p2.mStrokeMiterlimit;
17097f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    returnPath.mStrokeLineCap = p1.mStrokeLineCap;
17107f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    if (returnPath.mStrokeLineCap == null) {
17117f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        returnPath.mStrokeLineCap = p2.mStrokeLineCap;
1712abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
17137f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    returnPath.mStrokeLineJoin = p1.mStrokeLineJoin;
17147f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    if (returnPath.mStrokeLineJoin == null) {
17157f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        returnPath.mStrokeLineJoin = p2.mStrokeLineJoin;
1716abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1717abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mFillRule = p1.mFillRule;
1718abb7d134c02ac60091108c491dafb00877093170John Hoford
1719abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mStrokeColor = rgbInterpolate(t, p1.mStrokeColor, p2.mStrokeColor);
1720abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mFillColor = rgbInterpolate(t, p1.mFillColor, p2.mFillColor);
1721abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mStrokeWidth = t1 * p1.mStrokeWidth + t * p2.mStrokeWidth;
1722abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mNumberOfStates = p1.mNumberOfStates;
1723abb7d134c02ac60091108c491dafb00877093170John Hoford                    for (int i = 0; i < returnPath.mNumberOfStates; i++) {
1724abb7d134c02ac60091108c491dafb00877093170John Hoford                        returnPath.mCheckState[i] = p1.mCheckState[i];
1725abb7d134c02ac60091108c491dafb00877093170John Hoford                        returnPath.mCheckValue[i] = p1.mCheckValue[i];
1726abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1727abb7d134c02ac60091108c491dafb00877093170John Hoford                    for (int i = 0; i < p2.mNumberOfStates; i++) {
1728abb7d134c02ac60091108c491dafb00877093170John Hoford                        returnPath.addStateFilter(p2.mCheckState[i], p2.mCheckValue[i]);
1729abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1730abb7d134c02ac60091108c491dafb00877093170John Hoford
1731abb7d134c02ac60091108c491dafb00877093170John Hoford                    int count = 0;
1732abb7d134c02ac60091108c491dafb00877093170John Hoford                    for (int i = 0; i < returnPath.mNumberOfStates; i++) {
1733abb7d134c02ac60091108c491dafb00877093170John Hoford                        if (returnPath.mCheckValue[i]) {
1734abb7d134c02ac60091108c491dafb00877093170John Hoford                            count++;
1735abb7d134c02ac60091108c491dafb00877093170John Hoford                        }
1736abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1737abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mNumberOfTrue = count;
1738abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1739abb7d134c02ac60091108c491dafb00877093170John Hoford                case LIMIT_ROTATE:
1740abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mRotate = t1 * p1.mRotate + t * p2.mRotate;
1741abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1742abb7d134c02ac60091108c491dafb00877093170John Hoford                case LIMIT_TRIM_PATH_END:
1743abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mTrimPathEnd = t1 * p1.mTrimPathEnd + t * p2.mTrimPathEnd;
1744abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1745abb7d134c02ac60091108c491dafb00877093170John Hoford                case LIMIT_TRIM_PATH_OFFSET:
1746abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mTrimPathOffset = t1 * p1.mTrimPathOffset + t * p2.mTrimPathOffset;
1747abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1748abb7d134c02ac60091108c491dafb00877093170John Hoford                case LIMIT_TRIM_PATH_START:
1749abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mTrimPathStart = t1 * p1.mTrimPathStart + t * p2.mTrimPathStart;
1750abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1751abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1752abb7d134c02ac60091108c491dafb00877093170John Hoford            return returnPath;
1753abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1754abb7d134c02ac60091108c491dafb00877093170John Hoford
17554b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private static int rgbInterpolate(float fraction, int startColor, int endColor) {
17564b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            if (startColor == endColor) {
17574b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                return startColor;
17584b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            } else if (startColor == 0) {
17594b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                return endColor;
17604b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            } else if (endColor == 0) {
17614b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                return startColor;
1762abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1763abb7d134c02ac60091108c491dafb00877093170John Hoford
17644b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final int startA = (startColor >> 24) & 0xff;
17654b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final int startR = (startColor >> 16) & 0xff;
17664b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final int startG = (startColor >> 8) & 0xff;
17674b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final int startB = startColor & 0xff;
17684b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
17694b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final int endA = (endColor >> 24) & 0xff;
17704b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final int endR = (endColor >> 16) & 0xff;
17714b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final int endG = (endColor >> 8) & 0xff;
17724b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final int endB = endColor & 0xff;
17734b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
17744b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            return ((startA + (int)(fraction * (endA - startA))) << 24) |
17754b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    ((startR + (int)(fraction * (endR - startR))) << 16) |
17764b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    ((startG + (int)(fraction * (endG - startG))) << 8) |
17774b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    ((startB + (int)(fraction * (endB - startB))));
1778abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1779abb7d134c02ac60091108c491dafb00877093170John Hoford
1780abb7d134c02ac60091108c491dafb00877093170John Hoford        public boolean isVisible(int[] state) {
1781abb7d134c02ac60091108c491dafb00877093170John Hoford            int match = 0;
1782abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < state.length; i++) {
1783abb7d134c02ac60091108c491dafb00877093170John Hoford                int v = getState(state[i]);
1784abb7d134c02ac60091108c491dafb00877093170John Hoford                if (v != STATE_UNDEFINED) {
1785abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (v==STATE_TRUE) {
1786abb7d134c02ac60091108c491dafb00877093170John Hoford                        match++;
1787abb7d134c02ac60091108c491dafb00877093170John Hoford                    } else {
1788abb7d134c02ac60091108c491dafb00877093170John Hoford                        return false;
1789abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1790abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1791abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1792abb7d134c02ac60091108c491dafb00877093170John Hoford            return match == mNumberOfTrue;
1793abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1794abb7d134c02ac60091108c491dafb00877093170John Hoford    }
1795abb7d134c02ac60091108c491dafb00877093170John Hoford
1796abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VNode {
17975c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private char mType;
17985c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private float[] mParams;
17999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1800abb7d134c02ac60091108c491dafb00877093170John Hoford        public VNode(char type, float[] params) {
18015c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mType = type;
18025c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mParams = params;
1803abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1804abb7d134c02ac60091108c491dafb00877093170John Hoford
1805abb7d134c02ac60091108c491dafb00877093170John Hoford        public VNode(VNode n) {
18065c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mType = n.mType;
18075c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mParams = Arrays.copyOf(n.mParams, n.mParams.length);
1808abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1809abb7d134c02ac60091108c491dafb00877093170John Hoford
1810abb7d134c02ac60091108c491dafb00877093170John Hoford        public VNode(VNode n1, VNode n2, float t) {
18115c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mType = n1.mType;
18125c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mParams = new float[n1.mParams.length];
1813abb7d134c02ac60091108c491dafb00877093170John Hoford            interpolate(n1, n2, t);
1814abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1815abb7d134c02ac60091108c491dafb00877093170John Hoford
1816abb7d134c02ac60091108c491dafb00877093170John Hoford        private boolean match(VNode n) {
18175c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            if (n.mType != mType) {
1818abb7d134c02ac60091108c491dafb00877093170John Hoford                return false;
1819abb7d134c02ac60091108c491dafb00877093170John Hoford            }
18205c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return (mParams.length == n.mParams.length);
1821abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1822abb7d134c02ac60091108c491dafb00877093170John Hoford
1823abb7d134c02ac60091108c491dafb00877093170John Hoford        public void interpolate(VNode n1, VNode n2, float t) {
18245c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            for (int i = 0; i < n1.mParams.length; i++) {
18255c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mParams[i] = n1.mParams[i] * (1 - t) + n2.mParams[i] * t;
1826abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1827abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1828abb7d134c02ac60091108c491dafb00877093170John Hoford
1829abb7d134c02ac60091108c491dafb00877093170John Hoford        public static void createPath(VNode[] node, Path path) {
18305c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            float[] current = new float[4];
183133ed52eff4b41f88858874e1af7723277a041b56ztenghui            char previousCommand = 'm';
1832abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < node.length; i++) {
183333ed52eff4b41f88858874e1af7723277a041b56ztenghui                addCommand(path, current, previousCommand, node[i].mType, node[i].mParams);
183433ed52eff4b41f88858874e1af7723277a041b56ztenghui                previousCommand = node[i].mType;
1835abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1836abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1837abb7d134c02ac60091108c491dafb00877093170John Hoford
183833ed52eff4b41f88858874e1af7723277a041b56ztenghui        private static void addCommand(Path path, float[] current,
183933ed52eff4b41f88858874e1af7723277a041b56ztenghui                char previousCmd, char cmd, float[] val) {
1840abb7d134c02ac60091108c491dafb00877093170John Hoford
1841abb7d134c02ac60091108c491dafb00877093170John Hoford            int incr = 2;
1842abb7d134c02ac60091108c491dafb00877093170John Hoford            float currentX = current[0];
1843abb7d134c02ac60091108c491dafb00877093170John Hoford            float currentY = current[1];
1844abb7d134c02ac60091108c491dafb00877093170John Hoford            float ctrlPointX = current[2];
1845abb7d134c02ac60091108c491dafb00877093170John Hoford            float ctrlPointY = current[3];
184633ed52eff4b41f88858874e1af7723277a041b56ztenghui            float reflectiveCtrlPointX;
184733ed52eff4b41f88858874e1af7723277a041b56ztenghui            float reflectiveCtrlPointY;
1848abb7d134c02ac60091108c491dafb00877093170John Hoford
1849abb7d134c02ac60091108c491dafb00877093170John Hoford            switch (cmd) {
1850abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'z':
1851abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'Z':
1852abb7d134c02ac60091108c491dafb00877093170John Hoford                    path.close();
1853abb7d134c02ac60091108c491dafb00877093170John Hoford                    return;
1854abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'm':
1855abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'M':
1856abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'l':
1857abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'L':
1858abb7d134c02ac60091108c491dafb00877093170John Hoford                case 't':
1859abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'T':
1860abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 2;
1861abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1862abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'h':
1863abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'H':
1864abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'v':
1865abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'V':
1866abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 1;
1867abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1868abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'c':
1869abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'C':
1870abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 6;
1871abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1872abb7d134c02ac60091108c491dafb00877093170John Hoford                case 's':
1873abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'S':
1874abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'q':
1875abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'Q':
1876abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 4;
1877abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1878abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'a':
1879abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'A':
1880abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 7;
1881abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1882abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1883abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int k = 0; k < val.length; k += incr) {
1884abb7d134c02ac60091108c491dafb00877093170John Hoford                // TODO: build test to prove all permutations work
1885abb7d134c02ac60091108c491dafb00877093170John Hoford                switch (cmd) {
1886abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'm': // moveto - Start a new sub-path (relative)
1887abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rMoveTo(val[k + 0], val[k + 1]);
1888abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1889abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1890abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1891abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'M': // moveto - Start a new sub-path
1892abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.moveTo(val[k + 0], val[k + 1]);
1893abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1894abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 1];
1895abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1896abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'l': // lineto - Draw a line from the current point (relative)
1897abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(val[k + 0], val[k + 1]);
1898abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1899abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1900abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1901abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'L': // lineto - Draw a line from the current point
1902abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(val[k + 0], val[k + 1]);
1903abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1904abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 1];
1905abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1906abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'z': // closepath - Close the current subpath
1907abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'Z': // closepath - Close the current subpath
1908abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.close();
1909abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1910abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'h': // horizontal lineto - Draws a horizontal line (relative)
1911abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(val[k + 0], 0);
1912abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1913abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1914abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'H': // horizontal lineto - Draws a horizontal line
1915abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(val[k + 0], currentY);
1916abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1917abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1918abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'v': // vertical lineto - Draws a vertical line from the current point (r)
1919abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(0, val[k + 0]);
1920abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 0];
1921abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1922abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'V': // vertical lineto - Draws a vertical line from the current point
1923abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(currentX, val[k + 0]);
1924abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 0];
1925abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1926abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'c': // curveto - Draws a cubic Bézier curve (relative)
192733ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.rCubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
192833ed52eff4b41f88858874e1af7723277a041b56ztenghui                                val[k + 4], val[k + 5]);
1929abb7d134c02ac60091108c491dafb00877093170John Hoford
1930abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX + val[k + 2];
1931abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY + val[k + 3];
1932abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 4];
1933abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 5];
1934abb7d134c02ac60091108c491dafb00877093170John Hoford
1935abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1936abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'C': // curveto - Draws a cubic Bézier curve
193733ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.cubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
193833ed52eff4b41f88858874e1af7723277a041b56ztenghui                                val[k + 4], val[k + 5]);
1939abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 4];
1940abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 5];
1941abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 2];
1942abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 3];
1943abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1944abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp)
194533ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = 0;
194633ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = 0;
194733ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'c' || previousCmd == 's'
194833ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'C' || previousCmd == 'S') {
194933ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = currentX - ctrlPointX;
195033ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = currentY - ctrlPointY;
195133ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
195233ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
1953abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1],
1954abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2], val[k + 3]);
1955abb7d134c02ac60091108c491dafb00877093170John Hoford
1956abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX + val[k + 0];
1957abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY + val[k + 1];
1958abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 2];
1959abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 3];
1960abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1961abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp)
196233ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = currentX;
196333ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = currentY;
196433ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'c' || previousCmd == 's'
196533ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'C' || previousCmd == 'S') {
196633ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
196733ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
196833ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
196933ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
197033ed52eff4b41f88858874e1af7723277a041b56ztenghui                                val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
1971abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 0];
1972abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 1];
197333ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentX = val[k + 2];
197433ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentY = val[k + 3];
1975abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1976abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'q': // Draws a quadratic Bézier (relative)
1977abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
197833ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointX = currentX + val[k + 0];
197933ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointY = currentY + val[k + 1];
1980abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 2];
1981abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 3];
1982abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1983abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'Q': // Draws a quadratic Bézier
1984abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
1985abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 0];
1986abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 1];
198733ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentX = val[k + 2];
198833ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentY = val[k + 3];
1989abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1990abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 't': // Draws a quadratic Bézier curve(reflective control point)(relative)
199133ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = 0;
199233ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = 0;
199333ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'q' || previousCmd == 't'
199433ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'Q' || previousCmd == 'T') {
199533ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = currentX - ctrlPointX;
199633ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = currentY - ctrlPointY;
199733ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
199833ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
1999abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1]);
2000175f3c892c2c0bd64e32484a2b430e7c59907243ztenghui                        ctrlPointX = currentX + reflectiveCtrlPointX;
2001175f3c892c2c0bd64e32484a2b430e7c59907243ztenghui                        ctrlPointY = currentY + reflectiveCtrlPointY;
2002abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
2003abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
2004abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
2005abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'T': // Draws a quadratic Bézier curve (reflective control point)
200633ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = currentX;
200733ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = currentY;
200833ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'q' || previousCmd == 't'
200933ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'Q' || previousCmd == 'T') {
201033ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
201133ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
201233ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
201333ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
2014abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1]);
201533ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointX = reflectiveCtrlPointX;
201633ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointY = reflectiveCtrlPointY;
2017abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
201833ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentY = val[k + 1];
2019abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
2020abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'a': // Draws an elliptical arc
2021abb7d134c02ac60091108c491dafb00877093170John Hoford                        // (rx ry x-axis-rotation large-arc-flag sweep-flag x y)
2022abb7d134c02ac60091108c491dafb00877093170John Hoford                        drawArc(path,
2023abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentX,
2024abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentY,
2025abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 5] + currentX,
2026abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 6] + currentY,
2027abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0],
2028abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
2029abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
2030abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3] != 0,
2031abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 4] != 0);
2032abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 5];
2033abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 6];
2034abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX;
2035abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY;
2036abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
2037abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'A': // Draws an elliptical arc
2038abb7d134c02ac60091108c491dafb00877093170John Hoford                        drawArc(path,
2039abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentX,
2040abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentY,
2041abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 5],
2042abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 6],
2043abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0],
2044abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
2045abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
2046abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3] != 0,
2047abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 4] != 0);
2048abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 5];
2049abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 6];
2050abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX;
2051abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY;
2052abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
2053abb7d134c02ac60091108c491dafb00877093170John Hoford                }
205433ed52eff4b41f88858874e1af7723277a041b56ztenghui                previousCmd = cmd;
2055abb7d134c02ac60091108c491dafb00877093170John Hoford            }
2056abb7d134c02ac60091108c491dafb00877093170John Hoford            current[0] = currentX;
2057abb7d134c02ac60091108c491dafb00877093170John Hoford            current[1] = currentY;
2058abb7d134c02ac60091108c491dafb00877093170John Hoford            current[2] = ctrlPointX;
2059abb7d134c02ac60091108c491dafb00877093170John Hoford            current[3] = ctrlPointY;
2060abb7d134c02ac60091108c491dafb00877093170John Hoford        }
2061abb7d134c02ac60091108c491dafb00877093170John Hoford
2062abb7d134c02ac60091108c491dafb00877093170John Hoford        private static void drawArc(Path p,
2063abb7d134c02ac60091108c491dafb00877093170John Hoford                float x0,
2064abb7d134c02ac60091108c491dafb00877093170John Hoford                float y0,
2065abb7d134c02ac60091108c491dafb00877093170John Hoford                float x1,
2066abb7d134c02ac60091108c491dafb00877093170John Hoford                float y1,
2067abb7d134c02ac60091108c491dafb00877093170John Hoford                float a,
2068abb7d134c02ac60091108c491dafb00877093170John Hoford                float b,
2069abb7d134c02ac60091108c491dafb00877093170John Hoford                float theta,
2070abb7d134c02ac60091108c491dafb00877093170John Hoford                boolean isMoreThanHalf,
2071abb7d134c02ac60091108c491dafb00877093170John Hoford                boolean isPositiveArc) {
2072abb7d134c02ac60091108c491dafb00877093170John Hoford
2073abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Convert rotation angle from degrees to radians */
2074abb7d134c02ac60091108c491dafb00877093170John Hoford            double thetaD = Math.toRadians(theta);
2075abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Pre-compute rotation matrix entries */
2076abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosTheta = Math.cos(thetaD);
2077abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinTheta = Math.sin(thetaD);
2078abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Transform (x0, y0) and (x1, y1) into unit space */
2079abb7d134c02ac60091108c491dafb00877093170John Hoford            /* using (inverse) rotation, followed by (inverse) scale */
2080abb7d134c02ac60091108c491dafb00877093170John Hoford            double x0p = (x0 * cosTheta + y0 * sinTheta) / a;
2081abb7d134c02ac60091108c491dafb00877093170John Hoford            double y0p = (-x0 * sinTheta + y0 * cosTheta) / b;
2082abb7d134c02ac60091108c491dafb00877093170John Hoford            double x1p = (x1 * cosTheta + y1 * sinTheta) / a;
2083abb7d134c02ac60091108c491dafb00877093170John Hoford            double y1p = (-x1 * sinTheta + y1 * cosTheta) / b;
2084abb7d134c02ac60091108c491dafb00877093170John Hoford
2085abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Compute differences and averages */
2086abb7d134c02ac60091108c491dafb00877093170John Hoford            double dx = x0p - x1p;
2087abb7d134c02ac60091108c491dafb00877093170John Hoford            double dy = y0p - y1p;
2088abb7d134c02ac60091108c491dafb00877093170John Hoford            double xm = (x0p + x1p) / 2;
2089abb7d134c02ac60091108c491dafb00877093170John Hoford            double ym = (y0p + y1p) / 2;
2090abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Solve for intersecting unit circles */
2091abb7d134c02ac60091108c491dafb00877093170John Hoford            double dsq = dx * dx + dy * dy;
2092abb7d134c02ac60091108c491dafb00877093170John Hoford            if (dsq == 0.0) {
2093abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.w(LOGTAG, " Points are coincident");
2094abb7d134c02ac60091108c491dafb00877093170John Hoford                return; /* Points are coincident */
2095abb7d134c02ac60091108c491dafb00877093170John Hoford            }
2096abb7d134c02ac60091108c491dafb00877093170John Hoford            double disc = 1.0 / dsq - 1.0 / 4.0;
2097abb7d134c02ac60091108c491dafb00877093170John Hoford            if (disc < 0.0) {
2098abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.w(LOGTAG, "Points are too far apart " + dsq);
2099abb7d134c02ac60091108c491dafb00877093170John Hoford                float adjust = (float) (Math.sqrt(dsq) / 1.99999);
2100abb7d134c02ac60091108c491dafb00877093170John Hoford                drawArc(p, x0, y0, x1, y1, a * adjust,
2101abb7d134c02ac60091108c491dafb00877093170John Hoford                        b * adjust, theta, isMoreThanHalf, isPositiveArc);
2102abb7d134c02ac60091108c491dafb00877093170John Hoford                return; /* Points are too far apart */
2103abb7d134c02ac60091108c491dafb00877093170John Hoford            }
2104abb7d134c02ac60091108c491dafb00877093170John Hoford            double s = Math.sqrt(disc);
2105abb7d134c02ac60091108c491dafb00877093170John Hoford            double sdx = s * dx;
2106abb7d134c02ac60091108c491dafb00877093170John Hoford            double sdy = s * dy;
2107abb7d134c02ac60091108c491dafb00877093170John Hoford            double cx;
2108abb7d134c02ac60091108c491dafb00877093170John Hoford            double cy;
2109abb7d134c02ac60091108c491dafb00877093170John Hoford            if (isMoreThanHalf == isPositiveArc) {
2110abb7d134c02ac60091108c491dafb00877093170John Hoford                cx = xm - sdy;
2111abb7d134c02ac60091108c491dafb00877093170John Hoford                cy = ym + sdx;
2112abb7d134c02ac60091108c491dafb00877093170John Hoford            } else {
2113abb7d134c02ac60091108c491dafb00877093170John Hoford                cx = xm + sdy;
2114abb7d134c02ac60091108c491dafb00877093170John Hoford                cy = ym - sdx;
2115abb7d134c02ac60091108c491dafb00877093170John Hoford            }
2116abb7d134c02ac60091108c491dafb00877093170John Hoford
2117abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta0 = Math.atan2((y0p - cy), (x0p - cx));
2118abb7d134c02ac60091108c491dafb00877093170John Hoford
2119abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta1 = Math.atan2((y1p - cy), (x1p - cx));
2120abb7d134c02ac60091108c491dafb00877093170John Hoford
2121abb7d134c02ac60091108c491dafb00877093170John Hoford            double sweep = (eta1 - eta0);
2122abb7d134c02ac60091108c491dafb00877093170John Hoford            if (isPositiveArc != (sweep >= 0)) {
2123abb7d134c02ac60091108c491dafb00877093170John Hoford                if (sweep > 0) {
2124abb7d134c02ac60091108c491dafb00877093170John Hoford                    sweep -= 2 * Math.PI;
2125abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
2126abb7d134c02ac60091108c491dafb00877093170John Hoford                    sweep += 2 * Math.PI;
2127abb7d134c02ac60091108c491dafb00877093170John Hoford                }
2128abb7d134c02ac60091108c491dafb00877093170John Hoford            }
2129abb7d134c02ac60091108c491dafb00877093170John Hoford
2130abb7d134c02ac60091108c491dafb00877093170John Hoford            cx *= a;
2131abb7d134c02ac60091108c491dafb00877093170John Hoford            cy *= b;
2132abb7d134c02ac60091108c491dafb00877093170John Hoford            double tcx = cx;
2133abb7d134c02ac60091108c491dafb00877093170John Hoford            cx = cx * cosTheta - cy * sinTheta;
2134abb7d134c02ac60091108c491dafb00877093170John Hoford            cy = tcx * sinTheta + cy * cosTheta;
2135abb7d134c02ac60091108c491dafb00877093170John Hoford
2136abb7d134c02ac60091108c491dafb00877093170John Hoford            arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep);
2137abb7d134c02ac60091108c491dafb00877093170John Hoford        }
2138abb7d134c02ac60091108c491dafb00877093170John Hoford
2139abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
2140abb7d134c02ac60091108c491dafb00877093170John Hoford         * Converts an arc to cubic Bezier segments and records them in p.
2141abb7d134c02ac60091108c491dafb00877093170John Hoford         *
2142abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param p The target for the cubic Bezier segments
2143abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param cx The x coordinate center of the ellipse
2144abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param cy The y coordinate center of the ellipse
2145abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param a The radius of the ellipse in the horizontal direction
2146abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param b The radius of the ellipse in the vertical direction
2147abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param e1x E(eta1) x coordinate of the starting point of the arc
2148abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param e1y E(eta2) y coordinate of the starting point of the arc
2149abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param theta The angle that the ellipse bounding rectangle makes with horizontal plane
2150abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param start The start angle of the arc on the ellipse
2151abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse
2152abb7d134c02ac60091108c491dafb00877093170John Hoford         */
2153abb7d134c02ac60091108c491dafb00877093170John Hoford        private static void arcToBezier(Path p,
2154abb7d134c02ac60091108c491dafb00877093170John Hoford                double cx,
2155abb7d134c02ac60091108c491dafb00877093170John Hoford                double cy,
2156abb7d134c02ac60091108c491dafb00877093170John Hoford                double a,
2157abb7d134c02ac60091108c491dafb00877093170John Hoford                double b,
2158abb7d134c02ac60091108c491dafb00877093170John Hoford                double e1x,
2159abb7d134c02ac60091108c491dafb00877093170John Hoford                double e1y,
2160abb7d134c02ac60091108c491dafb00877093170John Hoford                double theta,
2161abb7d134c02ac60091108c491dafb00877093170John Hoford                double start,
2162abb7d134c02ac60091108c491dafb00877093170John Hoford                double sweep) {
2163abb7d134c02ac60091108c491dafb00877093170John Hoford            // Taken from equations at: http://spaceroots.org/documents/ellipse/node8.html
2164abb7d134c02ac60091108c491dafb00877093170John Hoford            // and http://www.spaceroots.org/documents/ellipse/node22.html
2165abb7d134c02ac60091108c491dafb00877093170John Hoford
2166abb7d134c02ac60091108c491dafb00877093170John Hoford            // Maximum of 45 degrees per cubic Bezier segment
2167abb7d134c02ac60091108c491dafb00877093170John Hoford            int numSegments = Math.abs((int) Math.ceil(sweep * 4 / Math.PI));
2168abb7d134c02ac60091108c491dafb00877093170John Hoford
2169abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta1 = start;
2170abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosTheta = Math.cos(theta);
2171abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinTheta = Math.sin(theta);
2172abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosEta1 = Math.cos(eta1);
2173abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinEta1 = Math.sin(eta1);
2174abb7d134c02ac60091108c491dafb00877093170John Hoford            double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1);
2175abb7d134c02ac60091108c491dafb00877093170John Hoford            double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1);
2176abb7d134c02ac60091108c491dafb00877093170John Hoford
2177abb7d134c02ac60091108c491dafb00877093170John Hoford            double anglePerSegment = sweep / numSegments;
2178abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < numSegments; i++) {
2179abb7d134c02ac60091108c491dafb00877093170John Hoford                double eta2 = eta1 + anglePerSegment;
2180abb7d134c02ac60091108c491dafb00877093170John Hoford                double sinEta2 = Math.sin(eta2);
2181abb7d134c02ac60091108c491dafb00877093170John Hoford                double cosEta2 = Math.cos(eta2);
2182abb7d134c02ac60091108c491dafb00877093170John Hoford                double e2x = cx + (a * cosTheta * cosEta2) - (b * sinTheta * sinEta2);
2183abb7d134c02ac60091108c491dafb00877093170John Hoford                double e2y = cy + (a * sinTheta * cosEta2) + (b * cosTheta * sinEta2);
2184abb7d134c02ac60091108c491dafb00877093170John Hoford                double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2;
2185abb7d134c02ac60091108c491dafb00877093170John Hoford                double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2;
2186abb7d134c02ac60091108c491dafb00877093170John Hoford                double tanDiff2 = Math.tan((eta2 - eta1) / 2);
2187abb7d134c02ac60091108c491dafb00877093170John Hoford                double alpha =
2188abb7d134c02ac60091108c491dafb00877093170John Hoford                        Math.sin(eta2 - eta1) * (Math.sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3;
2189abb7d134c02ac60091108c491dafb00877093170John Hoford                double q1x = e1x + alpha * ep1x;
2190abb7d134c02ac60091108c491dafb00877093170John Hoford                double q1y = e1y + alpha * ep1y;
2191abb7d134c02ac60091108c491dafb00877093170John Hoford                double q2x = e2x - alpha * ep2x;
2192abb7d134c02ac60091108c491dafb00877093170John Hoford                double q2y = e2y - alpha * ep2y;
2193abb7d134c02ac60091108c491dafb00877093170John Hoford
2194abb7d134c02ac60091108c491dafb00877093170John Hoford                p.cubicTo((float) q1x,
2195abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q1y,
2196abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q2x,
2197abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q2y,
2198abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) e2x,
2199abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) e2y);
2200abb7d134c02ac60091108c491dafb00877093170John Hoford                eta1 = eta2;
2201abb7d134c02ac60091108c491dafb00877093170John Hoford                e1x = e2x;
2202abb7d134c02ac60091108c491dafb00877093170John Hoford                e1y = e2y;
2203abb7d134c02ac60091108c491dafb00877093170John Hoford                ep1x = ep2x;
2204abb7d134c02ac60091108c491dafb00877093170John Hoford                ep1y = ep2y;
2205abb7d134c02ac60091108c491dafb00877093170John Hoford            }
2206abb7d134c02ac60091108c491dafb00877093170John Hoford        }
2207abb7d134c02ac60091108c491dafb00877093170John Hoford
2208abb7d134c02ac60091108c491dafb00877093170John Hoford    }
2209abb7d134c02ac60091108c491dafb00877093170John Hoford}
2210