VectorDrawable.java revision 4b3988d159e1c9faa2a7e16c9aca9951264bb429
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;
33abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.view.animation.AccelerateDecelerateInterpolator;
34abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.view.animation.Interpolator;
35abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.view.animation.LinearInterpolator;
36abb7d134c02ac60091108c491dafb00877093170John Hoford
37abb7d134c02ac60091108c491dafb00877093170John Hofordimport com.android.internal.R;
38abb7d134c02ac60091108c491dafb00877093170John Hoford
39abb7d134c02ac60091108c491dafb00877093170John Hofordimport org.xmlpull.v1.XmlPullParser;
40abb7d134c02ac60091108c491dafb00877093170John Hofordimport org.xmlpull.v1.XmlPullParserException;
41abb7d134c02ac60091108c491dafb00877093170John Hoford
42abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.io.IOException;
43abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.ArrayList;
44abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.Arrays;
45abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.Collection;
46abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.HashMap;
47abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.HashSet;
484b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
49abb7d134c02ac60091108c491dafb00877093170John Hoford/**
50abb7d134c02ac60091108c491dafb00877093170John Hoford * This lets you create a drawable based on an XML vector graphic
51abb7d134c02ac60091108c491dafb00877093170John Hoford * It can be defined in an XML file with the <code>&lt;vector></code> element.
52abb7d134c02ac60091108c491dafb00877093170John Hoford * <p/>
53abb7d134c02ac60091108c491dafb00877093170John Hoford * The vector drawable has 6 elements:
54abb7d134c02ac60091108c491dafb00877093170John Hoford * <p/>
55abb7d134c02ac60091108c491dafb00877093170John Hoford * <dl>
56177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui * <dt><code>&lt;vector></code></dt>
57fba3bad3870d607ecaed4f147788885c841c2ab3ztenghui * <dd>The attribute <code>android:trigger</code> defines a state change that
58abb7d134c02ac60091108c491dafb00877093170John Hoford * will drive the animation </dd>
59fba3bad3870d607ecaed4f147788885c841c2ab3ztenghui * <dd>The attribute <code>android:versionCode</code> defines the version of
60177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui * VectorDrawable </dd>
61abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;size></code></dt>
62abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Used to defined the intrinsic Width Height size of the drawable using
63abb7d134c02ac60091108c491dafb00877093170John Hoford * <code>android:width</code> and <code>android:height</code> </dd>
64abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;viewport></code></dt>
65abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Used to defined the size of the virtual canvas the paths are drawn on.
66abb7d134c02ac60091108c491dafb00877093170John Hoford * The size is defined using the attributes <code>android:viewportHeight
67abb7d134c02ac60091108c491dafb00877093170John Hoford * </code> <code>android:viewportWidth</code></dd>
68abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;group></code></dt>
69abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines a "key frame" in the animation if there is only one group the
70abb7d134c02ac60091108c491dafb00877093170John Hoford * drawable is static 2D image that has no animation.</dd>
71abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;path></code></dt>
72abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines paths to be drawn. The path elements must be within a group
73abb7d134c02ac60091108c491dafb00877093170John Hoford * <dl>
74abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:name</code>
75abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines the name of the path.</dd></dt>
76abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pathData</code>
77abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines path string.</dd></dt>
78abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:fill</code>
79abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines the color to fill the path (none if not present).</dd></dt>
80abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:stroke</code>
81abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines the color to draw the path outline (none if not present).</dd></dt>
82abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeWidth</code>
83abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The width a path stroke</dd></dt>
84abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeOpacity</code>
85abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The opacity of a path stroke</dd></dt>
86abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:rotation</code>
87abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The amount to rotation the path stroke.</dd></dt>
88abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pivotX</code>
89abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The X coordinate of the center of rotation of a path</dd></dt>
90abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pivotY</code>
91abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The Y coordinate of the center of rotation of a path</dd></dt>
92abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:fillOpacity</code>
93abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The opacity to fill the path with</dd></dt>
94abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathStart</code>
95abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The fraction of the path to trim from the start from 0 to 1</dd></dt>
96abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathEnd</code>
97abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The fraction of the path to trim from the end from 0 to 1</dd></dt>
98abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathOffset</code>
99abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Shift trim region (allows showed region to include the start and end) from 0 to 1</dd></dt>
100abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:clipToPath</code>
101abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Path will set the clip path</dd></dt>
102abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeLineCap</code>
103abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the linecap for a stroked path: butt, round, square</dd></dt>
104abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeLineJoin</code>
105abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the lineJoin for a stroked path: miter,round,bevel</dd></dt>
106abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeMiterLimit</code>
107abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the Miter limit for a stroked path</dd></dt>
108abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_pressed</code>
109abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
110abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_focused</code>
111abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
112abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_selected</code>
113abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
114abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_window_focused</code>
115abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
116abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_enabled</code>
117abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
118abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_activated</code>
119abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
120abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_accelerated</code>
121abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
122abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_hovered</code>
123abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
124abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_checked</code>
125abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
126abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:state_checkable</code>
127abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets a condition to be met to draw path</dd></dt>
128abb7d134c02ac60091108c491dafb00877093170John Hoford * </dl>
129abb7d134c02ac60091108c491dafb00877093170John Hoford * </dd>
130abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;animation></code></dt>
131abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Used to customize the transition between two paths
132abb7d134c02ac60091108c491dafb00877093170John Hoford * <dl>
133abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:sequence</code>
134abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Configures this animation sequence between the named paths.</dd></dt>
135abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:limitTo</code>
136abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Limits an animation to only interpolate the selected variable
137abb7d134c02ac60091108c491dafb00877093170John Hoford * unlimited, path, rotation, trimPathStart, trimPathEnd, trimPathOffset</dd></dt>
138abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:repeatCount</code>
139abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Number of times to loop this aspect of the animation</dd></dt>
140abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:durations</code>
141abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The duration of each step in the animation in milliseconds
142abb7d134c02ac60091108c491dafb00877093170John Hoford * Must contain the number of named paths - 1</dd></dt>
143abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:startDelay</code>
144abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd></dd></dt>
145abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:repeatStyle</code>
146abb7d134c02ac60091108c491dafb00877093170John Hoford *  <dd>when repeating how does it repeat back and forth or a to b: forward, inAndOut</dd></dt>
147abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:animate</code>
148abb7d134c02ac60091108c491dafb00877093170John Hoford *  <dd>linear, accelerate, decelerate, easing</dd></dt>
149abb7d134c02ac60091108c491dafb00877093170John Hoford * </dl>
150abb7d134c02ac60091108c491dafb00877093170John Hoford * </dd>
151abb7d134c02ac60091108c491dafb00877093170John Hoford */
152abb7d134c02ac60091108c491dafb00877093170John Hofordpublic class VectorDrawable extends Drawable {
1539453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    private static final String LOGTAG = VectorDrawable.class.getSimpleName();
1549453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
155abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_SIZE = "size";
156abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_VIEWPORT = "viewport";
157abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_GROUP = "group";
158abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_PATH = "path";
159abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_TRANSITION = "transition";
160abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_ANIMATION = "animation";
161abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_VECTOR = "vector";
162abb7d134c02ac60091108c491dafb00877093170John Hoford
163abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINECAP_BUTT = 0;
164abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINECAP_ROUND = 1;
165abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINECAP_SQUARE = 2;
1669453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
167abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINEJOIN_MITER = 0;
168abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINEJOIN_ROUND = 1;
169abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINEJOIN_BEVEL = 2;
1709453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
171abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int DEFAULT_DURATION = 1000;
172abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final long DEFAULT_INFINITE_DURATION = 60 * 60 * 1000;
1739453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1744b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette    private final VectorDrawableState mVectorState;
1754b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
176abb7d134c02ac60091108c491dafb00877093170John Hoford    private int mAlpha = 0xFF;
177abb7d134c02ac60091108c491dafb00877093170John Hoford
178abb7d134c02ac60091108c491dafb00877093170John Hoford    public VectorDrawable() {
1799453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        mVectorState = new VectorDrawableState(null);
180abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mBasicAnimator = ObjectAnimator.ofFloat(this, "AnimationFraction", 0, 1);
1819453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
182abb7d134c02ac60091108c491dafb00877093170John Hoford        setDuration(DEFAULT_DURATION);
183abb7d134c02ac60091108c491dafb00877093170John Hoford    }
184abb7d134c02ac60091108c491dafb00877093170John Hoford
1859453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    private VectorDrawable(VectorDrawableState state, Resources res, Theme theme) {
186abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState = new VectorDrawableState(state);
187abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mBasicAnimator = ObjectAnimator.ofFloat(this, "AnimationFraction", 0, 1);
1889453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1899453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        if (theme != null && canApplyTheme()) {
1909453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            applyTheme(theme);
1919453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
1929453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
193abb7d134c02ac60091108c491dafb00877093170John Hoford        long duration = mVectorState.mVAnimatedPath.getTotalAnimationDuration();
194abb7d134c02ac60091108c491dafb00877093170John Hoford        if (duration == -1) { // if it set to infinite set to 1 hour
195abb7d134c02ac60091108c491dafb00877093170John Hoford            duration = DEFAULT_INFINITE_DURATION; // TODO define correct approach for infinite
196abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mBasicAnimator.setFloatValues(0, duration / 1000);
197abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mBasicAnimator.setInterpolator(new LinearInterpolator());
198abb7d134c02ac60091108c491dafb00877093170John Hoford        }
199abb7d134c02ac60091108c491dafb00877093170John Hoford        setDuration(duration);
200abb7d134c02ac60091108c491dafb00877093170John Hoford    }
201abb7d134c02ac60091108c491dafb00877093170John Hoford
202abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
203abb7d134c02ac60091108c491dafb00877093170John Hoford    public ConstantState getConstantState() {
204abb7d134c02ac60091108c491dafb00877093170John Hoford        return mVectorState;
205abb7d134c02ac60091108c491dafb00877093170John Hoford    }
206abb7d134c02ac60091108c491dafb00877093170John Hoford
207abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
2085c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * Starts the animation.
209abb7d134c02ac60091108c491dafb00877093170John Hoford     */
210abb7d134c02ac60091108c491dafb00877093170John Hoford    public void start() {
211abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mBasicAnimator.start();
212abb7d134c02ac60091108c491dafb00877093170John Hoford    }
213abb7d134c02ac60091108c491dafb00877093170John Hoford
214abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
2155c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * Stops the animation.
216abb7d134c02ac60091108c491dafb00877093170John Hoford     */
217abb7d134c02ac60091108c491dafb00877093170John Hoford    public void stop() {
218abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mBasicAnimator.end();
219abb7d134c02ac60091108c491dafb00877093170John Hoford    }
220abb7d134c02ac60091108c491dafb00877093170John Hoford
221abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
2225c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * Returns the current completion value for the animation.
223abb7d134c02ac60091108c491dafb00877093170John Hoford     *
2245c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * @return the current point on the animation, typically between 0 and 1
225abb7d134c02ac60091108c491dafb00877093170John Hoford     */
226abb7d134c02ac60091108c491dafb00877093170John Hoford    public float geAnimationFraction() {
227abb7d134c02ac60091108c491dafb00877093170John Hoford        return mVectorState.mVAnimatedPath.getValue();
228abb7d134c02ac60091108c491dafb00877093170John Hoford    }
229abb7d134c02ac60091108c491dafb00877093170John Hoford
230abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
2315c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * Set the current completion value for the animation.
232abb7d134c02ac60091108c491dafb00877093170John Hoford     *
2335c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * @param value the point along the animation, typically between 0 and 1
234abb7d134c02ac60091108c491dafb00877093170John Hoford     */
235abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setAnimationFraction(float value) {
236abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mVAnimatedPath.setAnimationFraction(value);
237abb7d134c02ac60091108c491dafb00877093170John Hoford        invalidateSelf();
238abb7d134c02ac60091108c491dafb00877093170John Hoford    }
239abb7d134c02ac60091108c491dafb00877093170John Hoford
240abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
241abb7d134c02ac60091108c491dafb00877093170John Hoford     * set the amount of time the animation will take
242abb7d134c02ac60091108c491dafb00877093170John Hoford     *
243abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param duration amount of time in milliseconds
244abb7d134c02ac60091108c491dafb00877093170John Hoford     */
245abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setDuration(long duration) {
246abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mBasicAnimator.setDuration(duration);
247abb7d134c02ac60091108c491dafb00877093170John Hoford    }
248abb7d134c02ac60091108c491dafb00877093170John Hoford
249abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
2505c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * Defines what this animation should do when it reaches the end. This
2515c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * setting is applied only when the repeat count is either greater than
2525c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * 0 or {@link ValueAnimator#INFINITE}.
2535c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     *
2545c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * @param mode the animation mode, either {@link ValueAnimator#RESTART}
2555c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     *        or {@link ValueAnimator#REVERSE}
256abb7d134c02ac60091108c491dafb00877093170John Hoford     */
257abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setRepeatMode(int mode) {
258abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mBasicAnimator.setRepeatMode(mode);
259abb7d134c02ac60091108c491dafb00877093170John Hoford    }
260abb7d134c02ac60091108c491dafb00877093170John Hoford
261abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
262abb7d134c02ac60091108c491dafb00877093170John Hoford     * Sets animation to repeat
263abb7d134c02ac60091108c491dafb00877093170John Hoford     *
264abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param repeat True if this drawable repeats its animation
265abb7d134c02ac60091108c491dafb00877093170John Hoford     */
266abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setRepeatCount(int repeat) {
267abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mBasicAnimator.setRepeatCount(repeat);
268abb7d134c02ac60091108c491dafb00877093170John Hoford    }
269abb7d134c02ac60091108c491dafb00877093170John Hoford
270abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
2715c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     * @return the animation repeat count, either a value greater than 0 or
2725c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette     *         {@link ValueAnimator#INFINITE}
273abb7d134c02ac60091108c491dafb00877093170John Hoford     */
274abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getRepeatCount() {
275abb7d134c02ac60091108c491dafb00877093170John Hoford        return mVectorState.mBasicAnimator.getRepeatCount();
276abb7d134c02ac60091108c491dafb00877093170John Hoford    }
277abb7d134c02ac60091108c491dafb00877093170John Hoford
278abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
279abb7d134c02ac60091108c491dafb00877093170John Hoford    public boolean isStateful() {
280abb7d134c02ac60091108c491dafb00877093170John Hoford        return true;
281abb7d134c02ac60091108c491dafb00877093170John Hoford    }
282abb7d134c02ac60091108c491dafb00877093170John Hoford
283abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
284abb7d134c02ac60091108c491dafb00877093170John Hoford    protected boolean onStateChange(int[] state) {
2854b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        super.onStateChange(state);
2864b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
287abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mVAnimatedPath.setState(state);
2884b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
2894b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        final int direction = mVectorState.mVAnimatedPath.getTrigger(state);
2904b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        if (direction > 0) {
291abb7d134c02ac60091108c491dafb00877093170John Hoford            animateForward();
2924b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        } else if (direction < 0) {
293abb7d134c02ac60091108c491dafb00877093170John Hoford            animateBackward();
294abb7d134c02ac60091108c491dafb00877093170John Hoford        }
2954b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
296abb7d134c02ac60091108c491dafb00877093170John Hoford        invalidateSelf();
297abb7d134c02ac60091108c491dafb00877093170John Hoford        return true;
298abb7d134c02ac60091108c491dafb00877093170John Hoford    }
299abb7d134c02ac60091108c491dafb00877093170John Hoford
300abb7d134c02ac60091108c491dafb00877093170John Hoford    private void animateForward(){
301abb7d134c02ac60091108c491dafb00877093170John Hoford        if (!mVectorState.mBasicAnimator.isStarted()) {
302abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mBasicAnimator.setFloatValues(0,1);
303abb7d134c02ac60091108c491dafb00877093170John Hoford            start();
304abb7d134c02ac60091108c491dafb00877093170John Hoford        }
305abb7d134c02ac60091108c491dafb00877093170John Hoford    }
306abb7d134c02ac60091108c491dafb00877093170John Hoford
307abb7d134c02ac60091108c491dafb00877093170John Hoford    private void animateBackward(){
308abb7d134c02ac60091108c491dafb00877093170John Hoford        if (!mVectorState.mBasicAnimator.isStarted()) {
309abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mBasicAnimator.setFloatValues(.99f,0);
310abb7d134c02ac60091108c491dafb00877093170John Hoford            start();
311abb7d134c02ac60091108c491dafb00877093170John Hoford        }
312abb7d134c02ac60091108c491dafb00877093170John Hoford    }
313abb7d134c02ac60091108c491dafb00877093170John Hoford
314abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
315abb7d134c02ac60091108c491dafb00877093170John Hoford    public void draw(Canvas canvas) {
3164b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        final int saveCount = canvas.save();
3174b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        final Rect bounds = getBounds();
3184b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        canvas.translate(bounds.left, bounds.top);
3194b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        mVectorState.mVAnimatedPath.draw(canvas, bounds.width(), bounds.height());
3204b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        canvas.restoreToCount(saveCount);
321abb7d134c02ac60091108c491dafb00877093170John Hoford    }
322abb7d134c02ac60091108c491dafb00877093170John Hoford
323abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
324abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setAlpha(int alpha) {
325abb7d134c02ac60091108c491dafb00877093170John Hoford        // TODO correct handling of transparent
326abb7d134c02ac60091108c491dafb00877093170John Hoford        if (mAlpha != alpha) {
327abb7d134c02ac60091108c491dafb00877093170John Hoford            mAlpha = alpha;
328abb7d134c02ac60091108c491dafb00877093170John Hoford            invalidateSelf();
329abb7d134c02ac60091108c491dafb00877093170John Hoford        }
330abb7d134c02ac60091108c491dafb00877093170John Hoford    }
331abb7d134c02ac60091108c491dafb00877093170John Hoford
332abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
333abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setColorFilter(ColorFilter colorFilter) {
334abb7d134c02ac60091108c491dafb00877093170John Hoford        // TODO: support color filter
335abb7d134c02ac60091108c491dafb00877093170John Hoford    }
336abb7d134c02ac60091108c491dafb00877093170John Hoford
337abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
338abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getOpacity() {
339abb7d134c02ac60091108c491dafb00877093170John Hoford        return PixelFormat.TRANSLUCENT;
340abb7d134c02ac60091108c491dafb00877093170John Hoford    }
341abb7d134c02ac60091108c491dafb00877093170John Hoford
342abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
343abb7d134c02ac60091108c491dafb00877093170John Hoford     * Sets padding for this shape, defined by a Rect object. Define the padding in the Rect object
344abb7d134c02ac60091108c491dafb00877093170John Hoford     * as: left, top, right, bottom.
345abb7d134c02ac60091108c491dafb00877093170John Hoford     */
346abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setPadding(Rect padding) {
347abb7d134c02ac60091108c491dafb00877093170John Hoford        setPadding(padding.left, padding.top, padding.right, padding.bottom);
348abb7d134c02ac60091108c491dafb00877093170John Hoford    }
349abb7d134c02ac60091108c491dafb00877093170John Hoford
350abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
351abb7d134c02ac60091108c491dafb00877093170John Hoford     * Sets padding for the shape.
352abb7d134c02ac60091108c491dafb00877093170John Hoford     *
353abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param left padding for the left side (in pixels)
354abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param top padding for the top (in pixels)
355abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param right padding for the right side (in pixels)
356abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param bottom padding for the bottom (in pixels)
357abb7d134c02ac60091108c491dafb00877093170John Hoford     */
358abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setPadding(int left, int top, int right, int bottom) {
359abb7d134c02ac60091108c491dafb00877093170John Hoford        if ((left | top | right | bottom) == 0) {
360abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mPadding = null;
361abb7d134c02ac60091108c491dafb00877093170John Hoford        } else {
362abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mVectorState.mPadding == null) {
363abb7d134c02ac60091108c491dafb00877093170John Hoford                mVectorState.mPadding = new Rect();
364abb7d134c02ac60091108c491dafb00877093170John Hoford            }
365abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mPadding.set(left, top, right, bottom);
366abb7d134c02ac60091108c491dafb00877093170John Hoford        }
367abb7d134c02ac60091108c491dafb00877093170John Hoford        invalidateSelf();
368abb7d134c02ac60091108c491dafb00877093170John Hoford    }
369abb7d134c02ac60091108c491dafb00877093170John Hoford
370abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
371abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getIntrinsicWidth() {
3724b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        return (int) mVectorState.mVAnimatedPath.mBaseWidth;
373abb7d134c02ac60091108c491dafb00877093170John Hoford    }
374abb7d134c02ac60091108c491dafb00877093170John Hoford
375abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
376abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getIntrinsicHeight() {
3774b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        return (int) mVectorState.mVAnimatedPath.mBaseHeight;
378abb7d134c02ac60091108c491dafb00877093170John Hoford    }
379abb7d134c02ac60091108c491dafb00877093170John Hoford
380abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
381abb7d134c02ac60091108c491dafb00877093170John Hoford    public boolean getPadding(Rect padding) {
382abb7d134c02ac60091108c491dafb00877093170John Hoford        if (mVectorState.mPadding != null) {
383abb7d134c02ac60091108c491dafb00877093170John Hoford            padding.set(mVectorState.mPadding);
384abb7d134c02ac60091108c491dafb00877093170John Hoford            return true;
385abb7d134c02ac60091108c491dafb00877093170John Hoford        } else {
386abb7d134c02ac60091108c491dafb00877093170John Hoford            return super.getPadding(padding);
387abb7d134c02ac60091108c491dafb00877093170John Hoford        }
388abb7d134c02ac60091108c491dafb00877093170John Hoford    }
389abb7d134c02ac60091108c491dafb00877093170John Hoford
390abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
391abb7d134c02ac60091108c491dafb00877093170John Hoford    public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
392abb7d134c02ac60091108c491dafb00877093170John Hoford            throws XmlPullParserException, IOException {
3939453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        final VAnimatedPath p = inflateInternal(res, parser, attrs, theme);
3949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        setAnimatedPath(p);
395abb7d134c02ac60091108c491dafb00877093170John Hoford    }
396abb7d134c02ac60091108c491dafb00877093170John Hoford
3979453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    @Override
3989453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    public boolean canApplyTheme() {
3999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        return super.canApplyTheme() || mVectorState != null && mVectorState.canApplyTheme();
4009453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    }
4019453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
4029453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    @Override
4039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    public void applyTheme(Theme t) {
4049453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        super.applyTheme(t);
4059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
4069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        final VectorDrawableState state = mVectorState;
4079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        final VAnimatedPath path = state.mVAnimatedPath;
4089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        if (path != null && path.canApplyTheme()) {
4099453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            path.applyTheme(t);
4109453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
4119453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    }
4129453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
4139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    private VAnimatedPath inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
4149453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            Theme theme) throws XmlPullParserException, IOException {
4159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        final VAnimatedPath animatedPath = new VAnimatedPath();
4169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
417abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noSizeTag = true;
418abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noViewportTag = true;
419abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noGroupTag = true;
420abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noPathTag = true;
4219453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
4229453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        VGroup currentGroup = null;
423abb7d134c02ac60091108c491dafb00877093170John Hoford
424abb7d134c02ac60091108c491dafb00877093170John Hoford        int eventType = parser.getEventType();
425abb7d134c02ac60091108c491dafb00877093170John Hoford        while (eventType != XmlPullParser.END_DOCUMENT) {
426abb7d134c02ac60091108c491dafb00877093170John Hoford            if (eventType == XmlPullParser.START_TAG) {
4279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final String tagName = parser.getName();
428abb7d134c02ac60091108c491dafb00877093170John Hoford                if (SHAPE_PATH.equals(tagName)) {
4299453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final VPath path = new VPath();
4309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    path.inflate(res, attrs, theme);
4319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    currentGroup.add(path);
432abb7d134c02ac60091108c491dafb00877093170John Hoford                    noPathTag = false;
433abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_ANIMATION.equals(tagName)) {
4349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final VAnimation anim = new VAnimation();
4359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    anim.inflate(animatedPath.mGroupList, res, attrs, theme);
436abb7d134c02ac60091108c491dafb00877093170John Hoford                    animatedPath.addAnimation(anim);
437abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_SIZE.equals(tagName)) {
438abb7d134c02ac60091108c491dafb00877093170John Hoford                    animatedPath.parseSize(res, attrs);
439abb7d134c02ac60091108c491dafb00877093170John Hoford                    noSizeTag = false;
440abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_VIEWPORT.equals(tagName)) {
441abb7d134c02ac60091108c491dafb00877093170John Hoford                    animatedPath.parseViewport(res, attrs);
442abb7d134c02ac60091108c491dafb00877093170John Hoford                    noViewportTag = false;
443abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_GROUP.equals(tagName)) {
4449453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    currentGroup = new VGroup();
445abb7d134c02ac60091108c491dafb00877093170John Hoford                    animatedPath.mGroupList.add(currentGroup);
446abb7d134c02ac60091108c491dafb00877093170John Hoford                    noGroupTag = false;
447abb7d134c02ac60091108c491dafb00877093170John Hoford                }  else if (SHAPE_VECTOR.equals(tagName)) {
4489453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final TypedArray a = res.obtainAttributes(attrs, R.styleable.VectorDrawable);
449abb7d134c02ac60091108c491dafb00877093170John Hoford                    animatedPath.setTrigger(a.getInteger(R.styleable.VectorDrawable_trigger, 0));
450177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui
451177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    // Parsing the version information.
452177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    // Right now, we only support version "1".
453177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    // If the xml didn't specify the version number, the default version is "1".
4549453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final int versionCode = a.getInt(R.styleable.VectorDrawable_versionCode, 1);
455177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    if (versionCode != 1) {
456177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                        throw new IllegalArgumentException(
457177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                                "So far, VectorDrawable only support version 1");
458177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    }
459177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui
460abb7d134c02ac60091108c491dafb00877093170John Hoford                    a.recycle();
461abb7d134c02ac60091108c491dafb00877093170John Hoford                }
462abb7d134c02ac60091108c491dafb00877093170John Hoford            }
4639453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
464abb7d134c02ac60091108c491dafb00877093170John Hoford            eventType = parser.next();
465abb7d134c02ac60091108c491dafb00877093170John Hoford        }
4669453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
467abb7d134c02ac60091108c491dafb00877093170John Hoford        if (noSizeTag || noViewportTag || noGroupTag || noPathTag) {
4689453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final StringBuffer tag = new StringBuffer();
4699453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
470abb7d134c02ac60091108c491dafb00877093170John Hoford            if (noSizeTag) {
4719453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_SIZE);
472abb7d134c02ac60091108c491dafb00877093170John Hoford            }
4739453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
474abb7d134c02ac60091108c491dafb00877093170John Hoford            if  (noViewportTag){
475abb7d134c02ac60091108c491dafb00877093170John Hoford                if (tag.length()>0) {
476abb7d134c02ac60091108c491dafb00877093170John Hoford                    tag.append(" & ");
477abb7d134c02ac60091108c491dafb00877093170John Hoford                }
4789453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_SIZE);
479abb7d134c02ac60091108c491dafb00877093170John Hoford            }
4809453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
481abb7d134c02ac60091108c491dafb00877093170John Hoford            if  (noGroupTag){
482abb7d134c02ac60091108c491dafb00877093170John Hoford                if (tag.length()>0) {
483abb7d134c02ac60091108c491dafb00877093170John Hoford                    tag.append(" & ");
484abb7d134c02ac60091108c491dafb00877093170John Hoford                }
4859453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_GROUP);
486abb7d134c02ac60091108c491dafb00877093170John Hoford            }
4879453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
488abb7d134c02ac60091108c491dafb00877093170John Hoford            if  (noPathTag){
489abb7d134c02ac60091108c491dafb00877093170John Hoford                if (tag.length()>0) {
490abb7d134c02ac60091108c491dafb00877093170John Hoford                    tag.append(" or ");
491abb7d134c02ac60091108c491dafb00877093170John Hoford                }
4929453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_PATH);
493abb7d134c02ac60091108c491dafb00877093170John Hoford            }
4949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
4959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            throw new XmlPullParserException("no " + tag + " defined");
496abb7d134c02ac60091108c491dafb00877093170John Hoford        }
4979453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
498abb7d134c02ac60091108c491dafb00877093170John Hoford        // post parse cleanup
499abb7d134c02ac60091108c491dafb00877093170John Hoford        animatedPath.parseFinish();
500abb7d134c02ac60091108c491dafb00877093170John Hoford        return animatedPath;
501abb7d134c02ac60091108c491dafb00877093170John Hoford    }
502abb7d134c02ac60091108c491dafb00877093170John Hoford
503abb7d134c02ac60091108c491dafb00877093170John Hoford    private void setAnimatedPath(VAnimatedPath animatedPath) {
504abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState.mVAnimatedPath = animatedPath;
5059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
506abb7d134c02ac60091108c491dafb00877093170John Hoford        long duration = mVectorState.mVAnimatedPath.getTotalAnimationDuration();
507abb7d134c02ac60091108c491dafb00877093170John Hoford        if (duration == -1) { // if it set to infinite set to 1 hour
508abb7d134c02ac60091108c491dafb00877093170John Hoford            duration = DEFAULT_INFINITE_DURATION; // TODO define correct approach for infinite
509abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mBasicAnimator.setFloatValues(0, duration / 1000);
510abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mBasicAnimator.setInterpolator(new LinearInterpolator());
511abb7d134c02ac60091108c491dafb00877093170John Hoford        }
512abb7d134c02ac60091108c491dafb00877093170John Hoford
5139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        setDuration(duration);
514abb7d134c02ac60091108c491dafb00877093170John Hoford        setAnimationFraction(0);
515abb7d134c02ac60091108c491dafb00877093170John Hoford    }
516abb7d134c02ac60091108c491dafb00877093170John Hoford
517abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
518abb7d134c02ac60091108c491dafb00877093170John Hoford    public boolean setVisible(boolean visible, boolean restart) {
519abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean changed = super.setVisible(visible, restart);
520abb7d134c02ac60091108c491dafb00877093170John Hoford        if (visible) {
521abb7d134c02ac60091108c491dafb00877093170John Hoford            if (changed || restart) {
522abb7d134c02ac60091108c491dafb00877093170John Hoford                setAnimationFraction(0);
523abb7d134c02ac60091108c491dafb00877093170John Hoford            }
524abb7d134c02ac60091108c491dafb00877093170John Hoford        } else {
525abb7d134c02ac60091108c491dafb00877093170John Hoford            stop();
526abb7d134c02ac60091108c491dafb00877093170John Hoford        }
527abb7d134c02ac60091108c491dafb00877093170John Hoford        return changed;
528abb7d134c02ac60091108c491dafb00877093170John Hoford    }
529abb7d134c02ac60091108c491dafb00877093170John Hoford
5305c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette    private static class VectorDrawableState extends ConstantState {
5315c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        int mChangingConfigurations;
5325c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        ValueAnimator mBasicAnimator;
5335c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        VAnimatedPath mVAnimatedPath;
5345c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        Rect mPadding;
5355c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
5365c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public VectorDrawableState(VectorDrawableState copy) {
5375c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            if (copy != null) {
5385c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mChangingConfigurations = copy.mChangingConfigurations;
5395c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mVAnimatedPath = new VAnimatedPath(copy.mVAnimatedPath);
5405c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mPadding = new Rect(copy.mPadding);
5415c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            }
5425c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
5435c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
5445c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
5455c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable() {
5465c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, null, null);
5475c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
5485c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
5495c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
5505c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable(Resources res) {
5515c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, res, null);
5525c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
5535c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
5545c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
5555c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable(Resources res, Theme theme) {
5565c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, res, theme);
5575c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
5585c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
5595c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
5605c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public int getChangingConfigurations() {
5615c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return mChangingConfigurations;
5625c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
5635c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette    }
5645c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
565abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VAnimatedPath {
5664b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private static final int [] TRIGGER_MAP = {
5674b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                0,
5684b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                R.attr.state_pressed,
5694b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                R.attr.state_focused,
5704b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                R.attr.state_hovered,
5714b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                R.attr.state_selected,
5724b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                R.attr.state_checkable,
5734b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                R.attr.state_checked,
5744b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                R.attr.state_activated,
5754b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                R.attr.state_focused
5764b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        };
5774b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
5784b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private final Path mPath = new Path();
5794b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private final Path mRenderPath = new Path();
5804b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private final Matrix mMatrix = new Matrix();
5814b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
5824b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private ArrayList<VAnimation> mCurrentAnimList;
583abb7d134c02ac60091108c491dafb00877093170John Hoford        private VPath[] mCurrentPaths;
5844b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private Paint mStrokePaint;
5854b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private Paint mFillPaint;
586abb7d134c02ac60091108c491dafb00877093170John Hoford        private PathMeasure mPathMeasure;
5874b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
588abb7d134c02ac60091108c491dafb00877093170John Hoford        private int[] mCurrentState = new int[0];
5894b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private float mAnimationValue;
5904b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private long mTotalDuration;
591abb7d134c02ac60091108c491dafb00877093170John Hoford        private int mTrigger;
592abb7d134c02ac60091108c491dafb00877093170John Hoford        private boolean mTriggerState;
5939453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
5949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        final ArrayList<VGroup> mGroupList = new ArrayList<VGroup>();
5959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
596abb7d134c02ac60091108c491dafb00877093170John Hoford        float mBaseWidth = 1;
597abb7d134c02ac60091108c491dafb00877093170John Hoford        float mBaseHeight = 1;
598abb7d134c02ac60091108c491dafb00877093170John Hoford        float mViewportWidth;
599abb7d134c02ac60091108c491dafb00877093170John Hoford        float mViewportHeight;
600abb7d134c02ac60091108c491dafb00877093170John Hoford
601abb7d134c02ac60091108c491dafb00877093170John Hoford        public VAnimatedPath() {
602abb7d134c02ac60091108c491dafb00877093170John Hoford        }
6039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
604abb7d134c02ac60091108c491dafb00877093170John Hoford        public VAnimatedPath(VAnimatedPath copy) {
605abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentAnimList = new ArrayList<VAnimation>(copy.mCurrentAnimList);
6069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            mGroupList.addAll(copy.mGroupList);
607abb7d134c02ac60091108c491dafb00877093170John Hoford            if (copy.mCurrentPaths != null) {
608abb7d134c02ac60091108c491dafb00877093170John Hoford                mCurrentPaths = new VPath[copy.mCurrentPaths.length];
609abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int i = 0; i < mCurrentPaths.length; i++) {
610abb7d134c02ac60091108c491dafb00877093170John Hoford                    mCurrentPaths[i] = new VPath(copy.mCurrentPaths[i]);
611abb7d134c02ac60091108c491dafb00877093170John Hoford                }
612abb7d134c02ac60091108c491dafb00877093170John Hoford            }
613abb7d134c02ac60091108c491dafb00877093170John Hoford            mAnimationValue = copy.mAnimationValue; // time goes from 0 to 1
614abb7d134c02ac60091108c491dafb00877093170John Hoford
615abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseWidth = copy.mBaseWidth;
616abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseHeight = copy.mBaseHeight;
617abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportWidth = copy.mViewportHeight;
618abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportHeight = copy.mViewportHeight;
619abb7d134c02ac60091108c491dafb00877093170John Hoford            mTotalDuration = copy.mTotalDuration;
620abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrigger = copy.mTrigger;
621abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentState = new int[0];
622abb7d134c02ac60091108c491dafb00877093170John Hoford        }
623abb7d134c02ac60091108c491dafb00877093170John Hoford
6249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean canApplyTheme() {
6259453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final ArrayList<VGroup> groups = mGroupList;
6269453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            for (int i = groups.size() - 1; i >= 0; i--) {
6279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final ArrayList<VPath> paths = groups.get(i).mVGList;
6289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                for (int j = paths.size() - 1; j >= 0; j--) {
6299453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final VPath path = paths.get(j);
6309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    if (path.canApplyTheme()) {
6319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                        return true;
6329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    }
6339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
6349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
6359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final ArrayList<VAnimation> anims = mCurrentAnimList;
6379453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            for (int i = anims.size() - 1; i >= 0; i--) {
6389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final VAnimation anim = anims.get(i);
6399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                if (anim.canApplyTheme()) {
6409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    return true;
6419453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
6429453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
6439453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6449453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return false;
6459453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
6469453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6479453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void applyTheme(Theme t) {
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                        path.applyTheme(t);
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                    anim.applyTheme(t);
6649453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
6659453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
6669453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
6679453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
668abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setTrigger(int trigger){
6694b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            mTrigger = VAnimatedPath.getStateForTrigger(trigger);
670abb7d134c02ac60091108c491dafb00877093170John Hoford        }
671abb7d134c02ac60091108c491dafb00877093170John Hoford
672abb7d134c02ac60091108c491dafb00877093170John Hoford        public long getTotalAnimationDuration() {
673abb7d134c02ac60091108c491dafb00877093170John Hoford            mTotalDuration = 0;
674abb7d134c02ac60091108c491dafb00877093170John Hoford            int size = mCurrentAnimList.size();
675abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < size; i++) {
676abb7d134c02ac60091108c491dafb00877093170John Hoford                VAnimation vAnimation = mCurrentAnimList.get(i);
677abb7d134c02ac60091108c491dafb00877093170John Hoford                long t = vAnimation.getTotalDuration();
678abb7d134c02ac60091108c491dafb00877093170John Hoford                if (t == -1) {
679abb7d134c02ac60091108c491dafb00877093170John Hoford                    mTotalDuration = -1;
680abb7d134c02ac60091108c491dafb00877093170John Hoford                    return -1;
681abb7d134c02ac60091108c491dafb00877093170John Hoford                }
682abb7d134c02ac60091108c491dafb00877093170John Hoford                mTotalDuration = Math.max(mTotalDuration, t);
683abb7d134c02ac60091108c491dafb00877093170John Hoford            }
684abb7d134c02ac60091108c491dafb00877093170John Hoford
685abb7d134c02ac60091108c491dafb00877093170John Hoford            return mTotalDuration;
686abb7d134c02ac60091108c491dafb00877093170John Hoford        }
687abb7d134c02ac60091108c491dafb00877093170John Hoford
688abb7d134c02ac60091108c491dafb00877093170John Hoford        public float getValue() {
689abb7d134c02ac60091108c491dafb00877093170John Hoford            return mAnimationValue;
690abb7d134c02ac60091108c491dafb00877093170John Hoford        }
691abb7d134c02ac60091108c491dafb00877093170John Hoford
692abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
693abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param value the point along the animations to show typically between 0.0f and 1.0f
694abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return true if you need to keep repeating
695abb7d134c02ac60091108c491dafb00877093170John Hoford         */
696abb7d134c02ac60091108c491dafb00877093170John Hoford        public boolean setAnimationFraction(float value) {
697abb7d134c02ac60091108c491dafb00877093170John Hoford            getTotalAnimationDuration();
6989453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
699abb7d134c02ac60091108c491dafb00877093170John Hoford            long animationTime = (long) (value * mTotalDuration);
700abb7d134c02ac60091108c491dafb00877093170John Hoford
7019453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int len = mCurrentPaths.length;
702abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < len; i++) {
703abb7d134c02ac60091108c491dafb00877093170John Hoford                animationTime =
704abb7d134c02ac60091108c491dafb00877093170John Hoford                        (long) ((mTotalDuration == -1) ? value * 1000 : mTotalDuration * value);
7059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final VPath path = mCurrentPaths[i];
7079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final int size = mCurrentAnimList.size();
708abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int j = 0; j < size; j++) {
7099453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final VAnimation vAnimation = mCurrentAnimList.get(j);
710abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (vAnimation.doesAdjustPath(path)) {
711abb7d134c02ac60091108c491dafb00877093170John Hoford                        mCurrentPaths[i] =  vAnimation.getPathAtTime(animationTime, path);
712abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
713abb7d134c02ac60091108c491dafb00877093170John Hoford                }
714abb7d134c02ac60091108c491dafb00877093170John Hoford            }
7159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            mAnimationValue = value;
7179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
718abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mTotalDuration == -1) {
719abb7d134c02ac60091108c491dafb00877093170John Hoford                return true;
720abb7d134c02ac60091108c491dafb00877093170John Hoford            } else {
721abb7d134c02ac60091108c491dafb00877093170John Hoford                return animationTime < mTotalDuration;
722abb7d134c02ac60091108c491dafb00877093170John Hoford            }
723abb7d134c02ac60091108c491dafb00877093170John Hoford        }
724abb7d134c02ac60091108c491dafb00877093170John Hoford
7254b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        public void draw(Canvas canvas, int w, int h) {
726abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mCurrentPaths == null) {
727abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.e(LOGTAG,"mCurrentPaths == null");
728abb7d134c02ac60091108c491dafb00877093170John Hoford                return;
729abb7d134c02ac60091108c491dafb00877093170John Hoford            }
730abb7d134c02ac60091108c491dafb00877093170John Hoford
731abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mCurrentPaths.length; i++) {
732abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mCurrentPaths[i] != null && mCurrentPaths[i].isVisible(mCurrentState)) {
733abb7d134c02ac60091108c491dafb00877093170John Hoford                    drawPath(mCurrentPaths[i], canvas, w, h);
734abb7d134c02ac60091108c491dafb00877093170John Hoford                }
735abb7d134c02ac60091108c491dafb00877093170John Hoford            }
736abb7d134c02ac60091108c491dafb00877093170John Hoford        }
737abb7d134c02ac60091108c491dafb00877093170John Hoford
738abb7d134c02ac60091108c491dafb00877093170John Hoford        private void drawPath(VPath vPath, Canvas canvas, int w, int h) {
7399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final float scale = Math.min(h / mViewportHeight, w / mViewportWidth);
740abb7d134c02ac60091108c491dafb00877093170John Hoford
741abb7d134c02ac60091108c491dafb00877093170John Hoford            vPath.toPath(mPath);
7424b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final Path path = mPath;
743abb7d134c02ac60091108c491dafb00877093170John Hoford
744abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mTrimPathStart != 0.0f || vPath.mTrimPathEnd != 1.0f) {
745abb7d134c02ac60091108c491dafb00877093170John Hoford                float start = (vPath.mTrimPathStart + vPath.mTrimPathOffset) % 1.0f;
746abb7d134c02ac60091108c491dafb00877093170John Hoford                float end = (vPath.mTrimPathEnd + vPath.mTrimPathOffset) % 1.0f;
747abb7d134c02ac60091108c491dafb00877093170John Hoford
748abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPathMeasure == null) {
749abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure = new PathMeasure();
750abb7d134c02ac60091108c491dafb00877093170John Hoford                }
751abb7d134c02ac60091108c491dafb00877093170John Hoford                mPathMeasure.setPath(mPath, false);
752abb7d134c02ac60091108c491dafb00877093170John Hoford
753abb7d134c02ac60091108c491dafb00877093170John Hoford                float len = mPathMeasure.getLength();
754abb7d134c02ac60091108c491dafb00877093170John Hoford                start = start * len;
755abb7d134c02ac60091108c491dafb00877093170John Hoford                end = end * len;
756abb7d134c02ac60091108c491dafb00877093170John Hoford                path.reset();
757abb7d134c02ac60091108c491dafb00877093170John Hoford                if (start > end) {
758abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure.getSegment(start, len, path, true);
759abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure.getSegment(0f, end, path, true);
760abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
761abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure.getSegment(start, end, path, true);
762abb7d134c02ac60091108c491dafb00877093170John Hoford                }
763abb7d134c02ac60091108c491dafb00877093170John Hoford                path.rLineTo(0, 0); // fix bug in measure
764abb7d134c02ac60091108c491dafb00877093170John Hoford            }
765abb7d134c02ac60091108c491dafb00877093170John Hoford
766abb7d134c02ac60091108c491dafb00877093170John Hoford            mRenderPath.reset();
767abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.reset();
768abb7d134c02ac60091108c491dafb00877093170John Hoford
769abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.postRotate(vPath.mRotate, vPath.mPivotX, vPath.mPivotY);
770abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.postScale(scale, scale, mViewportWidth / 2f, mViewportHeight / 2f);
771abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.postTranslate(w / 2f - mViewportWidth / 2f, h / 2f - mViewportHeight / 2f);
772abb7d134c02ac60091108c491dafb00877093170John Hoford
773abb7d134c02ac60091108c491dafb00877093170John Hoford            mRenderPath.addPath(path, mMatrix);
774abb7d134c02ac60091108c491dafb00877093170John Hoford
775abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mClip) {
776abb7d134c02ac60091108c491dafb00877093170John Hoford                canvas.clipPath(mRenderPath, Region.Op.REPLACE);
777abb7d134c02ac60091108c491dafb00877093170John Hoford            }
7789453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
779abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mFillColor != 0) {
7804b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                if (mFillPaint == null) {
7814b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mFillPaint = new Paint();
7824b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mFillPaint.setStyle(Paint.Style.FILL);
7834b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mFillPaint.setAntiAlias(true);
7844b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                }
7854b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
786abb7d134c02ac60091108c491dafb00877093170John Hoford                mFillPaint.setColor(vPath.mFillColor);
787abb7d134c02ac60091108c491dafb00877093170John Hoford                canvas.drawPath(mRenderPath, mFillPaint);
788abb7d134c02ac60091108c491dafb00877093170John Hoford            }
7899453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
790abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mStrokeColor != 0) {
7914b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                if (mStrokePaint == null) {
7924b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mStrokePaint = new Paint();
7934b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mStrokePaint.setStyle(Paint.Style.STROKE);
7944b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mStrokePaint.setAntiAlias(true);
7954b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                }
7964b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
7974b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                final Paint strokePaint = mStrokePaint;
7987f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                if (vPath.mStrokeLineJoin != null) {
7994b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    strokePaint.setStrokeJoin(vPath.mStrokeLineJoin);
800abb7d134c02ac60091108c491dafb00877093170John Hoford                }
8014b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
8027f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                if (vPath.mStrokeLineCap != null) {
8034b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    strokePaint.setStrokeCap(vPath.mStrokeLineCap);
804abb7d134c02ac60091108c491dafb00877093170John Hoford                }
8054b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
8064b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                strokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale);
8074b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                strokePaint.setColor(vPath.mStrokeColor);
8084b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                strokePaint.setStrokeWidth(vPath.mStrokeWidth * scale);
8094b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                canvas.drawPath(mRenderPath, strokePaint);
810abb7d134c02ac60091108c491dafb00877093170John Hoford            }
811abb7d134c02ac60091108c491dafb00877093170John Hoford        }
812abb7d134c02ac60091108c491dafb00877093170John Hoford
813abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
814abb7d134c02ac60091108c491dafb00877093170John Hoford         * Ensure there is at least one animation for every path in group (linking them by names)
815abb7d134c02ac60091108c491dafb00877093170John Hoford         * Build the "current" path based on the first group
816abb7d134c02ac60091108c491dafb00877093170John Hoford         * TODO: improve memory use & performance or move to C++
817abb7d134c02ac60091108c491dafb00877093170John Hoford         */
818abb7d134c02ac60091108c491dafb00877093170John Hoford        public void parseFinish() {
8199453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final HashMap<String, VAnimation> newAnimations = new HashMap<String, VAnimation>();
820abb7d134c02ac60091108c491dafb00877093170John Hoford            for (VGroup group : mGroupList) {
821abb7d134c02ac60091108c491dafb00877093170John Hoford                for (VPath vPath : group.getPaths()) {
822abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (!vPath.mAnimated) {
823abb7d134c02ac60091108c491dafb00877093170John Hoford                        VAnimation ap = null;
824abb7d134c02ac60091108c491dafb00877093170John Hoford
825abb7d134c02ac60091108c491dafb00877093170John Hoford                        if (!newAnimations.containsKey(vPath.getID())) {
826abb7d134c02ac60091108c491dafb00877093170John Hoford                            newAnimations.put(vPath.getID(), ap = new VAnimation());
827abb7d134c02ac60091108c491dafb00877093170John Hoford                        } else {
828abb7d134c02ac60091108c491dafb00877093170John Hoford                            ap = newAnimations.get(vPath.getID());
829abb7d134c02ac60091108c491dafb00877093170John Hoford                        }
8309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
831abb7d134c02ac60091108c491dafb00877093170John Hoford                        ap.addPath(vPath);
832abb7d134c02ac60091108c491dafb00877093170John Hoford                        vPath.mAnimated = true;
833abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
834abb7d134c02ac60091108c491dafb00877093170John Hoford                }
835abb7d134c02ac60091108c491dafb00877093170John Hoford            }
8369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
837abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mCurrentAnimList == null) {
838abb7d134c02ac60091108c491dafb00877093170John Hoford                mCurrentAnimList = new ArrayList<VectorDrawable.VAnimation>();
839abb7d134c02ac60091108c491dafb00877093170John Hoford            }
840abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentAnimList.addAll(newAnimations.values());
8419453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
8429453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final Collection<VPath> paths = mGroupList.get(0).getPaths();
843abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentPaths = paths.toArray(new VPath[paths.size()]);
844abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mCurrentPaths.length; i++) {
845abb7d134c02ac60091108c491dafb00877093170John Hoford                mCurrentPaths[i] = new VPath(mCurrentPaths[i]);
846abb7d134c02ac60091108c491dafb00877093170John Hoford            }
847abb7d134c02ac60091108c491dafb00877093170John Hoford        }
848abb7d134c02ac60091108c491dafb00877093170John Hoford
849abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setState(int[] state) {
850abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentState = Arrays.copyOf(state, state.length);
851abb7d134c02ac60091108c491dafb00877093170John Hoford        }
852abb7d134c02ac60091108c491dafb00877093170John Hoford
853abb7d134c02ac60091108c491dafb00877093170John Hoford        int getTrigger(int []state){
854abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mTrigger == 0) return 0;
855abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < state.length; i++) {
856abb7d134c02ac60091108c491dafb00877093170John Hoford                if (state[i] == mTrigger){
857abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (mTriggerState)
858abb7d134c02ac60091108c491dafb00877093170John Hoford                        return 0;
859abb7d134c02ac60091108c491dafb00877093170John Hoford                    mTriggerState = true;
860abb7d134c02ac60091108c491dafb00877093170John Hoford                    return 1;
861abb7d134c02ac60091108c491dafb00877093170John Hoford                }
862abb7d134c02ac60091108c491dafb00877093170John Hoford            }
863abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mTriggerState) {
864abb7d134c02ac60091108c491dafb00877093170John Hoford                mTriggerState = false;
865abb7d134c02ac60091108c491dafb00877093170John Hoford                return -1;
866abb7d134c02ac60091108c491dafb00877093170John Hoford            }
867abb7d134c02ac60091108c491dafb00877093170John Hoford            return 0;
868abb7d134c02ac60091108c491dafb00877093170John Hoford        }
869abb7d134c02ac60091108c491dafb00877093170John Hoford
870abb7d134c02ac60091108c491dafb00877093170John Hoford        public void addAnimation(VAnimation anim) {
871abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mCurrentAnimList == null) {
872abb7d134c02ac60091108c491dafb00877093170John Hoford                mCurrentAnimList = new ArrayList<VectorDrawable.VAnimation>();
873abb7d134c02ac60091108c491dafb00877093170John Hoford            }
874abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentAnimList.add(anim);
875abb7d134c02ac60091108c491dafb00877093170John Hoford        }
876abb7d134c02ac60091108c491dafb00877093170John Hoford
877abb7d134c02ac60091108c491dafb00877093170John Hoford        private void parseViewport(Resources r, AttributeSet attrs)
878abb7d134c02ac60091108c491dafb00877093170John Hoford                throws XmlPullParserException {
8794b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport);
880abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportWidth = a.getFloat(R.styleable.VectorDrawableViewport_viewportWidth, 0);
881abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportHeight = a.getFloat(R.styleable.VectorDrawableViewport_viewportHeight, 0);
882abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mViewportWidth == 0 || mViewportHeight == 0) {
883abb7d134c02ac60091108c491dafb00877093170John Hoford                throw new XmlPullParserException(a.getPositionDescription()+
884abb7d134c02ac60091108c491dafb00877093170John Hoford                        "<viewport> tag requires viewportWidth & viewportHeight to be set");
885abb7d134c02ac60091108c491dafb00877093170John Hoford            }
886abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
887abb7d134c02ac60091108c491dafb00877093170John Hoford        }
888abb7d134c02ac60091108c491dafb00877093170John Hoford
889abb7d134c02ac60091108c491dafb00877093170John Hoford        private void parseSize(Resources r, AttributeSet attrs)
890abb7d134c02ac60091108c491dafb00877093170John Hoford                throws XmlPullParserException  {
8914b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableSize);
892abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseWidth = a.getDimension(R.styleable.VectorDrawableSize_width, 0);
893abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseHeight = a.getDimension(R.styleable.VectorDrawableSize_height, 0);
894abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mBaseWidth == 0 || mBaseHeight == 0) {
895abb7d134c02ac60091108c491dafb00877093170John Hoford                throw new XmlPullParserException(a.getPositionDescription()+
896abb7d134c02ac60091108c491dafb00877093170John Hoford                        "<size> tag requires width & height to be set");
897abb7d134c02ac60091108c491dafb00877093170John Hoford            }
898abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
899abb7d134c02ac60091108c491dafb00877093170John Hoford        }
9004b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
9014b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private static final int getStateForTrigger(int trigger) {
9024b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            return TRIGGER_MAP[trigger];
9034b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        }
904abb7d134c02ac60091108c491dafb00877093170John Hoford    }
905abb7d134c02ac60091108c491dafb00877093170John Hoford
906abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VAnimation {
9075c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private static final String SEPARATOR = ",";
9089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
9095c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private static final int DIRECTION_FORWARD = 0;
9105c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private static final int DIRECTION_IN_AND_OUT = 1;
911abb7d134c02ac60091108c491dafb00877093170John Hoford
912abb7d134c02ac60091108c491dafb00877093170John Hoford        public enum Style {
913abb7d134c02ac60091108c491dafb00877093170John Hoford            INTERPOLATE, CROSSFADE, WIPE
914abb7d134c02ac60091108c491dafb00877093170John Hoford        }
9159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
9165c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private final HashSet<String> mSeqMap = new HashSet<String>();
9175c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
9185c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private Interpolator mAnimInterpolator = new AccelerateDecelerateInterpolator();
9195c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private VPath[] mPaths = new VPath[0];
9205c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private long[] mDuration = { DEFAULT_DURATION };
9219453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
9229453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private int[] mThemeAttrs;
923abb7d134c02ac60091108c491dafb00877093170John Hoford        private Style mStyle;
924abb7d134c02ac60091108c491dafb00877093170John Hoford        private int mLimitProperty = 0;
925abb7d134c02ac60091108c491dafb00877093170John Hoford        private long mStartOffset;
926abb7d134c02ac60091108c491dafb00877093170John Hoford        private long mRepeat = 1;
927abb7d134c02ac60091108c491dafb00877093170John Hoford        private long mWipeDirection;
9285c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private int mMode = DIRECTION_FORWARD;
929abb7d134c02ac60091108c491dafb00877093170John Hoford        private int mInterpolatorType;
930abb7d134c02ac60091108c491dafb00877093170John Hoford        private String mId;
931abb7d134c02ac60091108c491dafb00877093170John Hoford
932abb7d134c02ac60091108c491dafb00877093170John Hoford        public VAnimation() {
9339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            // Empty constructor.
934abb7d134c02ac60091108c491dafb00877093170John Hoford        }
935abb7d134c02ac60091108c491dafb00877093170John Hoford
9369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void inflate(ArrayList<VGroup> groups, Resources r, AttributeSet attrs, Theme theme)
937abb7d134c02ac60091108c491dafb00877093170John Hoford                throws XmlPullParserException {
938abb7d134c02ac60091108c491dafb00877093170John Hoford            String value;
939abb7d134c02ac60091108c491dafb00877093170John Hoford            String[] sp;
940abb7d134c02ac60091108c491dafb00877093170John Hoford            int name;
941abb7d134c02ac60091108c491dafb00877093170John Hoford
9429453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableAnimation);
9435c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            final int[] themeAttrs = a.extractThemeAttrs();
9445c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mThemeAttrs = themeAttrs;
945abb7d134c02ac60091108c491dafb00877093170John Hoford
946abb7d134c02ac60091108c491dafb00877093170John Hoford            value = a.getString(R.styleable.VectorDrawableAnimation_sequence);
947abb7d134c02ac60091108c491dafb00877093170John Hoford            if (value != null) {
9485c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                sp = value.split(SEPARATOR);
9495c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                final VectorDrawable.VPath[] paths = new VectorDrawable.VPath[sp.length];
950abb7d134c02ac60091108c491dafb00877093170John Hoford
951abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int j = 0; j < sp.length; j++) {
952abb7d134c02ac60091108c491dafb00877093170John Hoford                    mSeqMap.add(sp[j].trim());
953abb7d134c02ac60091108c491dafb00877093170John Hoford                    VectorDrawable.VPath path = groups.get(j).get(sp[j]);
954abb7d134c02ac60091108c491dafb00877093170John Hoford                    path.mAnimated = true;
955abb7d134c02ac60091108c491dafb00877093170John Hoford                    paths[j] = path;
956abb7d134c02ac60091108c491dafb00877093170John Hoford                }
9575c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
958abb7d134c02ac60091108c491dafb00877093170John Hoford                setPaths(paths);
959abb7d134c02ac60091108c491dafb00877093170John Hoford            }
960abb7d134c02ac60091108c491dafb00877093170John Hoford
961abb7d134c02ac60091108c491dafb00877093170John Hoford            name = R.styleable.VectorDrawableAnimation_durations;
962abb7d134c02ac60091108c491dafb00877093170John Hoford            value = a.getString(name);
963abb7d134c02ac60091108c491dafb00877093170John Hoford            if (value != null) {
964abb7d134c02ac60091108c491dafb00877093170John Hoford                long totalDuration = 0;
9655c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                sp = value.split(SEPARATOR);
9669453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
9679453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final long[] dur = new long[sp.length];
968abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int j = 0; j < dur.length; j++) {
969abb7d134c02ac60091108c491dafb00877093170John Hoford                    dur[j] = Long.parseLong(sp[j]);
970abb7d134c02ac60091108c491dafb00877093170John Hoford                    totalDuration +=  dur[j];
971abb7d134c02ac60091108c491dafb00877093170John Hoford                }
9729453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
973abb7d134c02ac60091108c491dafb00877093170John Hoford                if (totalDuration == 0){
9745c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                    throw new XmlPullParserException(a.getPositionDescription()
9755c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                            + " total duration must not be zero");
976abb7d134c02ac60091108c491dafb00877093170John Hoford                }
9779453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
978abb7d134c02ac60091108c491dafb00877093170John Hoford                setDuration(dur);
979abb7d134c02ac60091108c491dafb00877093170John Hoford            }
980abb7d134c02ac60091108c491dafb00877093170John Hoford
9815c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            setLimitProperty(a.getInt(R.styleable.VectorDrawableAnimation_limitTo, 0));
982abb7d134c02ac60091108c491dafb00877093170John Hoford            setRepeat(a.getInt(R.styleable.VectorDrawableAnimation_repeatCount, 1));
983abb7d134c02ac60091108c491dafb00877093170John Hoford            setStartOffset(a.getInt(R.styleable.VectorDrawableAnimation_startDelay, 0));
984abb7d134c02ac60091108c491dafb00877093170John Hoford            setMode(a.getInt(R.styleable.VectorDrawableAnimation_repeatStyle, 0));
985abb7d134c02ac60091108c491dafb00877093170John Hoford
986abb7d134c02ac60091108c491dafb00877093170John Hoford            fixMissingParameters();
9879453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
988abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
989abb7d134c02ac60091108c491dafb00877093170John Hoford        }
990abb7d134c02ac60091108c491dafb00877093170John Hoford
9919453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean canApplyTheme() {
9929453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return mThemeAttrs != null;
9939453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
9949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
9959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void applyTheme(Theme t) {
9969453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            // TODO: Apply theme.
9979453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
9989453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
9999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean doesAdjustPath(VPath path) {
10009453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return mSeqMap.contains(path.getID());
10019453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
10029453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1003abb7d134c02ac60091108c491dafb00877093170John Hoford        public String getId() {
1004abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mId == null) {
1005abb7d134c02ac60091108c491dafb00877093170John Hoford                mId = mPaths[0].getID();
1006abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int i = 1; i < mPaths.length; i++) {
1007abb7d134c02ac60091108c491dafb00877093170John Hoford                    mId += mPaths[i].getID();
1008abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1009abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1010abb7d134c02ac60091108c491dafb00877093170John Hoford            return mId;
1011abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1012abb7d134c02ac60091108c491dafb00877093170John Hoford
1013abb7d134c02ac60091108c491dafb00877093170John Hoford        public String getPathName() {
1014abb7d134c02ac60091108c491dafb00877093170John Hoford            return mPaths[0].getID();
1015abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1016abb7d134c02ac60091108c491dafb00877093170John Hoford
1017abb7d134c02ac60091108c491dafb00877093170John Hoford        public Style getStyle() {
1018abb7d134c02ac60091108c491dafb00877093170John Hoford            return mStyle;
1019abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1020abb7d134c02ac60091108c491dafb00877093170John Hoford
1021abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setStyle(Style style) {
10225c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mStyle = style;
1023abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1024abb7d134c02ac60091108c491dafb00877093170John Hoford
1025abb7d134c02ac60091108c491dafb00877093170John Hoford        public int getLimitProperty() {
1026abb7d134c02ac60091108c491dafb00877093170John Hoford            return mLimitProperty;
1027abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1028abb7d134c02ac60091108c491dafb00877093170John Hoford
1029abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setLimitProperty(int limitProperty) {
10305c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mLimitProperty = limitProperty;
1031abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1032abb7d134c02ac60091108c491dafb00877093170John Hoford
1033abb7d134c02ac60091108c491dafb00877093170John Hoford        public long[] getDuration() {
1034abb7d134c02ac60091108c491dafb00877093170John Hoford            return mDuration;
1035abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1036abb7d134c02ac60091108c491dafb00877093170John Hoford
1037abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setDuration(long[] duration) {
10385c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mDuration = duration;
1039abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1040abb7d134c02ac60091108c491dafb00877093170John Hoford
1041abb7d134c02ac60091108c491dafb00877093170John Hoford        public long getRepeat() {
1042abb7d134c02ac60091108c491dafb00877093170John Hoford            return mRepeat;
1043abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1044abb7d134c02ac60091108c491dafb00877093170John Hoford
1045abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setRepeat(long repeat) {
10465c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mRepeat = repeat;
1047abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1048abb7d134c02ac60091108c491dafb00877093170John Hoford
1049abb7d134c02ac60091108c491dafb00877093170John Hoford        public long getStartOffset() {
1050abb7d134c02ac60091108c491dafb00877093170John Hoford            return mStartOffset;
1051abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1052abb7d134c02ac60091108c491dafb00877093170John Hoford
1053abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setStartOffset(long startOffset) {
10545c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mStartOffset = startOffset;
1055abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1056abb7d134c02ac60091108c491dafb00877093170John Hoford
1057abb7d134c02ac60091108c491dafb00877093170John Hoford        public long getWipeDirection() {
1058abb7d134c02ac60091108c491dafb00877093170John Hoford            return mWipeDirection;
1059abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1060abb7d134c02ac60091108c491dafb00877093170John Hoford
1061abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setWipeDirection(long wipeDirection) {
10625c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mWipeDirection = wipeDirection;
1063abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1064abb7d134c02ac60091108c491dafb00877093170John Hoford
1065abb7d134c02ac60091108c491dafb00877093170John Hoford        public int getMode() {
1066abb7d134c02ac60091108c491dafb00877093170John Hoford            return mMode;
1067abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1068abb7d134c02ac60091108c491dafb00877093170John Hoford
1069abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setMode(int mode) {
10705c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mMode = mode;
1071abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1072abb7d134c02ac60091108c491dafb00877093170John Hoford
1073abb7d134c02ac60091108c491dafb00877093170John Hoford        public int getInterpolator() {
1074abb7d134c02ac60091108c491dafb00877093170John Hoford            return mInterpolatorType;
1075abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1076abb7d134c02ac60091108c491dafb00877093170John Hoford
1077abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setInterpolator(int interpolator) {
10785c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mInterpolatorType = interpolator;
1079abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1080abb7d134c02ac60091108c491dafb00877093170John Hoford
1081abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1082abb7d134c02ac60091108c491dafb00877093170John Hoford         * compute the total time in milliseconds
1083abb7d134c02ac60091108c491dafb00877093170John Hoford         *
1084abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return the total time in milliseconds the animation will take
1085abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1086abb7d134c02ac60091108c491dafb00877093170John Hoford        public long getTotalDuration() {
1087abb7d134c02ac60091108c491dafb00877093170John Hoford            long total = mStartOffset;
1088abb7d134c02ac60091108c491dafb00877093170John Hoford            if (getRepeat() == -1) {
1089abb7d134c02ac60091108c491dafb00877093170John Hoford                return -1;
1090abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1091abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mDuration.length; i++) {
1092abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mRepeat > 1) {
1093abb7d134c02ac60091108c491dafb00877093170John Hoford                    total += mDuration[i] * mRepeat;
1094abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
1095abb7d134c02ac60091108c491dafb00877093170John Hoford                    total += mDuration[i];
1096abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1097abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1098abb7d134c02ac60091108c491dafb00877093170John Hoford            return total;
1099abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1100abb7d134c02ac60091108c491dafb00877093170John Hoford
1101abb7d134c02ac60091108c491dafb00877093170John Hoford        public void setPaths(VPath[] paths) {
11029453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            mPaths = paths;
1103abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1104abb7d134c02ac60091108c491dafb00877093170John Hoford
1105abb7d134c02ac60091108c491dafb00877093170John Hoford        public void addPath(VPath path) {
1106abb7d134c02ac60091108c491dafb00877093170John Hoford            mPaths = Arrays.copyOf(mPaths, mPaths.length + 1);
1107abb7d134c02ac60091108c491dafb00877093170John Hoford            mPaths[mPaths.length - 1] = path;
1108abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1109abb7d134c02ac60091108c491dafb00877093170John Hoford
1110abb7d134c02ac60091108c491dafb00877093170John Hoford        public boolean containsPath(String pathid) {
1111abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mPaths.length; i++) {
1112abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPaths[i].getID().equals(pathid)) {
1113abb7d134c02ac60091108c491dafb00877093170John Hoford                    return true;
1114abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1115abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1116abb7d134c02ac60091108c491dafb00877093170John Hoford            return false;
1117abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1118abb7d134c02ac60091108c491dafb00877093170John Hoford
1119abb7d134c02ac60091108c491dafb00877093170John Hoford        public void interpolate(VPath p1, VPath p2, float time, VPath dest) {
11209453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            VPath.interpolate(time, p1, p2, dest, mLimitProperty);
1121abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1122abb7d134c02ac60091108c491dafb00877093170John Hoford
1123abb7d134c02ac60091108c491dafb00877093170John Hoford        public VPath getPathAtTime(long milliseconds, VPath dest) {
1124abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mPaths.length == 1) {
1125abb7d134c02ac60091108c491dafb00877093170John Hoford                dest.copyFrom(mPaths[0]);
1126abb7d134c02ac60091108c491dafb00877093170John Hoford                return dest;
1127abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1128abb7d134c02ac60091108c491dafb00877093170John Hoford            long point = milliseconds - mStartOffset;
1129abb7d134c02ac60091108c491dafb00877093170John Hoford            if (point < 0) {
1130abb7d134c02ac60091108c491dafb00877093170John Hoford                point = 0;
1131abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1132abb7d134c02ac60091108c491dafb00877093170John Hoford            float time = 0;
1133abb7d134c02ac60091108c491dafb00877093170John Hoford            long sum = mDuration[0];
1134abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 1; i < mDuration.length; i++) {
1135abb7d134c02ac60091108c491dafb00877093170John Hoford                sum += mDuration[i];
1136abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1137abb7d134c02ac60091108c491dafb00877093170John Hoford
1138abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mRepeat > 1) {
1139abb7d134c02ac60091108c491dafb00877093170John Hoford                time = point / (float) (sum * mRepeat);
1140abb7d134c02ac60091108c491dafb00877093170John Hoford                time = mAnimInterpolator.getInterpolation(time);
1141abb7d134c02ac60091108c491dafb00877093170John Hoford
1142abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mMode == DIRECTION_IN_AND_OUT) {
1143abb7d134c02ac60091108c491dafb00877093170John Hoford                    point = ((long) (time * sum * 2 * mRepeat)) % (sum * 2);
1144abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (point > sum) {
1145abb7d134c02ac60091108c491dafb00877093170John Hoford                        point = sum * 2 - point;
1146abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1147abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
1148abb7d134c02ac60091108c491dafb00877093170John Hoford                    point = ((long) (time * sum * mRepeat)) % sum;
1149abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1150abb7d134c02ac60091108c491dafb00877093170John Hoford            } else if (mRepeat == 1) {
1151abb7d134c02ac60091108c491dafb00877093170John Hoford                time = point / (float) (sum * mRepeat);
1152abb7d134c02ac60091108c491dafb00877093170John Hoford                time = mAnimInterpolator.getInterpolation(time);
1153abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mMode == DIRECTION_IN_AND_OUT) {
1154abb7d134c02ac60091108c491dafb00877093170John Hoford                    point = ((long) (time * sum * 2 * mRepeat));
1155abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (point > sum) {
1156abb7d134c02ac60091108c491dafb00877093170John Hoford                        point = sum * 2 - point;
1157abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1158abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
1159abb7d134c02ac60091108c491dafb00877093170John Hoford                    point = Math.min(((long) (time * sum * mRepeat)), sum);
1160abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1161abb7d134c02ac60091108c491dafb00877093170John Hoford
1162abb7d134c02ac60091108c491dafb00877093170John Hoford            } else { // repeat = -1
1163abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mMode == DIRECTION_IN_AND_OUT) {
1164abb7d134c02ac60091108c491dafb00877093170John Hoford                    point = point % (sum * 2);
1165abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (point > sum) {
1166abb7d134c02ac60091108c491dafb00877093170John Hoford                        point = sum * 2 - point;
1167abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1168abb7d134c02ac60091108c491dafb00877093170John Hoford                    time = point / (float) sum;
1169abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
1170abb7d134c02ac60091108c491dafb00877093170John Hoford                    point = point % sum;
1171abb7d134c02ac60091108c491dafb00877093170John Hoford                    time = point / (float) sum;
1172abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1173abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1174abb7d134c02ac60091108c491dafb00877093170John Hoford
1175abb7d134c02ac60091108c491dafb00877093170John Hoford            int transition = 0;
1176abb7d134c02ac60091108c491dafb00877093170John Hoford            while (point > mDuration[transition]) {
1177abb7d134c02ac60091108c491dafb00877093170John Hoford                point -= mDuration[transition++];
1178abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1179abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mPaths.length > (transition + 1)) {
1180abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPaths[transition].getID() != dest.getID()) {
1181abb7d134c02ac60091108c491dafb00877093170John Hoford                    dest.copyFrom(mPaths[transition]);
1182abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1183abb7d134c02ac60091108c491dafb00877093170John Hoford                interpolate(mPaths[transition], mPaths[transition + 1],
1184abb7d134c02ac60091108c491dafb00877093170John Hoford                        point / (float) mDuration[transition], dest);
1185abb7d134c02ac60091108c491dafb00877093170John Hoford            } else {
1186abb7d134c02ac60091108c491dafb00877093170John Hoford                interpolate(mPaths[transition], mPaths[transition], 0, dest);
1187abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1188abb7d134c02ac60091108c491dafb00877093170John Hoford            return dest;
1189abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1190abb7d134c02ac60091108c491dafb00877093170John Hoford
1191abb7d134c02ac60091108c491dafb00877093170John Hoford        void fixMissingParameters() {
1192abb7d134c02ac60091108c491dafb00877093170John Hoford            // fix missing points
1193abb7d134c02ac60091108c491dafb00877093170John Hoford            float rotation = Float.NaN;
1194abb7d134c02ac60091108c491dafb00877093170John Hoford            float rotationY = Float.NaN;
1195abb7d134c02ac60091108c491dafb00877093170John Hoford            float rotationX = Float.NaN;
1196abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mPaths.length; i++) {
1197abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPaths[i].mPivotX > 0) {
1198abb7d134c02ac60091108c491dafb00877093170John Hoford                    rotationX = mPaths[i].mPivotX;
1199abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1200abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPaths[i].mPivotY > 0) {
1201abb7d134c02ac60091108c491dafb00877093170John Hoford                    rotationY = mPaths[i].mPivotY;
1202abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1203abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPaths[i].mRotate > 0) {
1204abb7d134c02ac60091108c491dafb00877093170John Hoford                    rotation = mPaths[i].mRotate;
1205abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1206abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1207abb7d134c02ac60091108c491dafb00877093170John Hoford            if (rotation > 0) {
1208abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int i = 0; i < mPaths.length; i++) {
1209abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (mPaths[i].mPivotX == 0) {
1210abb7d134c02ac60091108c491dafb00877093170John Hoford                        mPaths[i].mPivotX = rotationX;
1211abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1212abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (mPaths[i].mPivotY == 0) {
1213abb7d134c02ac60091108c491dafb00877093170John Hoford                        mPaths[i].mPivotY = rotationY;
1214abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1215abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1216abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1217abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1218abb7d134c02ac60091108c491dafb00877093170John Hoford    }
1219abb7d134c02ac60091108c491dafb00877093170John Hoford
1220abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VGroup {
12219453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private final HashMap<String, VPath> mVGPathMap = new HashMap<String, VPath>();
12229453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private final ArrayList<VPath> mVGList = new ArrayList<VPath>();
1223abb7d134c02ac60091108c491dafb00877093170John Hoford
1224abb7d134c02ac60091108c491dafb00877093170John Hoford        public void add(VPath path) {
1225abb7d134c02ac60091108c491dafb00877093170John Hoford            String id = path.getID();
1226abb7d134c02ac60091108c491dafb00877093170John Hoford            mVGPathMap.put(id, path);
1227abb7d134c02ac60091108c491dafb00877093170John Hoford            mVGList.add(path);
1228abb7d134c02ac60091108c491dafb00877093170John Hoford         }
1229abb7d134c02ac60091108c491dafb00877093170John Hoford
1230abb7d134c02ac60091108c491dafb00877093170John Hoford        public VPath get(String name) {
1231abb7d134c02ac60091108c491dafb00877093170John Hoford            return mVGPathMap.get(name);
1232abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1233abb7d134c02ac60091108c491dafb00877093170John Hoford
1234abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1235abb7d134c02ac60091108c491dafb00877093170John Hoford         * Must return in order of adding
1236abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return ordered list of paths
1237abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1238abb7d134c02ac60091108c491dafb00877093170John Hoford        public Collection<VPath> getPaths() {
1239abb7d134c02ac60091108c491dafb00877093170John Hoford            return mVGList;
1240abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1241abb7d134c02ac60091108c491dafb00877093170John Hoford
1242abb7d134c02ac60091108c491dafb00877093170John Hoford        public int size() {
1243abb7d134c02ac60091108c491dafb00877093170John Hoford            return mVGPathMap.size();
1244abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1245abb7d134c02ac60091108c491dafb00877093170John Hoford    }
1246abb7d134c02ac60091108c491dafb00877093170John Hoford
1247abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VPath {
1248abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int LIMIT_ALL = 0;
1249abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int LIMIT_PATH = 1;
1250abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int LIMIT_ROTATE = 2;
1251abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int LIMIT_TRIM_PATH_START = 3;
1252abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int LIMIT_TRIM_PATH_OFFSET = 5;
1253abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int LIMIT_TRIM_PATH_END = 4;
12549453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1255abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int STATE_UNDEFINED=0;
1256abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int STATE_TRUE=1;
1257abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int STATE_FALSE=2;
12589453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1259abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int MAX_STATES = 10;
12609453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
12619453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private int[] mThemeAttrs;
12629453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1263abb7d134c02ac60091108c491dafb00877093170John Hoford        int mStrokeColor = 0;
1264abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeWidth = 0;
1265abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeOpacity = Float.NaN;
12669453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1267abb7d134c02ac60091108c491dafb00877093170John Hoford        int mFillColor = 0;
1268abb7d134c02ac60091108c491dafb00877093170John Hoford        int mFillRule;
1269abb7d134c02ac60091108c491dafb00877093170John Hoford        float mFillOpacity = Float.NaN;
12709453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1271abb7d134c02ac60091108c491dafb00877093170John Hoford        float mRotate = 0;
1272abb7d134c02ac60091108c491dafb00877093170John Hoford        float mPivotX = 0;
1273abb7d134c02ac60091108c491dafb00877093170John Hoford        float mPivotY = 0;
12749453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1275abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathStart = 0;
1276abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathEnd = 1;
1277abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathOffset = 0;
12789453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1279abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean mAnimated = false;
1280abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean mClip = false;
12814b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        Paint.Cap mStrokeLineCap = Paint.Cap.BUTT;
12824b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        Paint.Join mStrokeLineJoin = Paint.Join.MITER;
1283abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeMiterlimit = 4;
12849453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
12859453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private VNode[] mNode = null;
12869453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private String mId;
1287abb7d134c02ac60091108c491dafb00877093170John Hoford        private int[] mCheckState = new int[MAX_STATES];
1288abb7d134c02ac60091108c491dafb00877093170John Hoford        private boolean[] mCheckValue = new boolean[MAX_STATES];
1289abb7d134c02ac60091108c491dafb00877093170John Hoford        private int mNumberOfStates = 0;
1290abb7d134c02ac60091108c491dafb00877093170John Hoford        private int mNumberOfTrue = 0;
1291abb7d134c02ac60091108c491dafb00877093170John Hoford
12929453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public VPath() {
12939453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            // Empty constructor.
12949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
12959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
12969453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public VPath(VPath p) {
12979453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            copyFrom(p);
12989453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
12999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1300abb7d134c02ac60091108c491dafb00877093170John Hoford        public void addStateFilter(int state, boolean condition) {
1301abb7d134c02ac60091108c491dafb00877093170John Hoford            int k = 0;
1302abb7d134c02ac60091108c491dafb00877093170John Hoford            while (k < mNumberOfStates) {
1303abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mCheckState[mNumberOfStates] == state)
1304abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1305abb7d134c02ac60091108c491dafb00877093170John Hoford                k++;
1306abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1307abb7d134c02ac60091108c491dafb00877093170John Hoford            mCheckState[k] = state;
1308abb7d134c02ac60091108c491dafb00877093170John Hoford            mCheckValue[k] = condition;
1309abb7d134c02ac60091108c491dafb00877093170John Hoford            if (k==mNumberOfStates){
1310abb7d134c02ac60091108c491dafb00877093170John Hoford                mNumberOfStates++;
1311abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1312abb7d134c02ac60091108c491dafb00877093170John Hoford            if (condition) {
1313abb7d134c02ac60091108c491dafb00877093170John Hoford                mNumberOfTrue++;
1314abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1315abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1316abb7d134c02ac60091108c491dafb00877093170John Hoford
13179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private int getState(int state){
1318abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mNumberOfStates; i++) {
1319abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mCheckState[mNumberOfStates] == state){
1320abb7d134c02ac60091108c491dafb00877093170John Hoford                    return (mCheckValue[i])?STATE_TRUE:STATE_FALSE;
1321abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1322abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1323abb7d134c02ac60091108c491dafb00877093170John Hoford            return STATE_UNDEFINED;
1324abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1325abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1326abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return the name of the path
1327abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1328abb7d134c02ac60091108c491dafb00877093170John Hoford        public String getName() {
1329abb7d134c02ac60091108c491dafb00877093170John Hoford            return mId;
1330abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1331abb7d134c02ac60091108c491dafb00877093170John Hoford
1332abb7d134c02ac60091108c491dafb00877093170John Hoford        public void toPath(Path path) {
1333abb7d134c02ac60091108c491dafb00877093170John Hoford            path.reset();
1334abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mNode != null) {
1335abb7d134c02ac60091108c491dafb00877093170John Hoford                VNode.createPath(mNode, path);
1336abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1337abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1338abb7d134c02ac60091108c491dafb00877093170John Hoford
13397f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        public String getID() {
1340abb7d134c02ac60091108c491dafb00877093170John Hoford            return mId;
1341abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1342abb7d134c02ac60091108c491dafb00877093170John Hoford
13437f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) {
13447f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            switch (id) {
13457f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_BUTT:
13467f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.BUTT;
13477f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_ROUND:
13487f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.ROUND;
13497f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_SQUARE:
13507f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.SQUARE;
13517f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                default:
13527f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return defValue;
13537f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
13547f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        }
13557f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
13567f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        private Paint.Join getStrokeLineJoin(int id, Paint.Join defValue) {
13577f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            switch (id) {
13587f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_MITER:
13597f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.MITER;
13607f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_ROUND:
13617f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.ROUND;
13627f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_BEVEL:
13637f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.BEVEL;
13647f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                default:
13657f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return defValue;
13667f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
13677f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        }
13687f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
13699453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void inflate(Resources r, AttributeSet attrs, Theme theme) {
13709453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawablePath);
13719453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int[] themeAttrs = a.extractThemeAttrs();
13729453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            mThemeAttrs = themeAttrs;
13739453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
13747f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            // NOTE: The set of attributes loaded here MUST match the
13757f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            // set of attributes loaded in applyTheme.
13767f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_clipToPath] == 0) {
13777f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
13787f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
13797f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
13807f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_name] == 0) {
13817f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mId = a.getString(R.styleable.VectorDrawablePath_name);
13827f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
13837f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
13847f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pathData] == 0) {
13857f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData));
13867f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
1387abb7d134c02ac60091108c491dafb00877093170John Hoford
13889453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fill] == 0) {
13897f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor);
13909453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
13919453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
13927f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fillOpacity] == 0) {
13937f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity);
1394abb7d134c02ac60091108c491dafb00877093170John Hoford            }
13959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
13967f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_rotation] == 0) {
13977f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mRotate = a.getFloat(R.styleable.VectorDrawablePath_rotation, mRotate);
13987f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
13999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14007f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pivotX] == 0) {
14017f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mPivotX = a.getFloat(R.styleable.VectorDrawablePath_pivotX, mPivotX);
1402abb7d134c02ac60091108c491dafb00877093170John Hoford            }
14039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14047f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pivotY] == 0) {
14057f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mPivotY = a.getFloat(R.styleable.VectorDrawablePath_pivotY, mPivotY);
14067f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14077f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
14087f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
14097f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeLineCap] == 0) {
14107f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeLineCap = getStrokeLineCap(
14117f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        a.getInt(R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
14127f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14137f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
14147f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
14157f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeLineJoin] == 0) {
14167f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeLineJoin = getStrokeLineJoin(
14177f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        a.getInt(R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
1418abb7d134c02ac60091108c491dafb00877093170John Hoford            }
14199453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14207f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
14217f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeMiterLimit] == 0) {
14227f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeMiterlimit = a.getFloat(
14237f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
14247f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14259453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14269453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_stroke] == 0) {
14279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor);
1428abb7d134c02ac60091108c491dafb00877093170John Hoford            }
14299453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null
14319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeOpacity] == 0) {
14329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeOpacity = a.getFloat(
14337f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity);
14349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
14359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14367f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_strokeWidth] == 0) {
14377f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth);
14387f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14397f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
14407f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_trimPathEnd] == 0) {
14417f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd);
14427f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14439453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14447f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
14457f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_trimPathOffset] == 0) {
14467f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathOffset = a.getFloat(
14477f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
14487f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14497f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
14507f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
14517f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_trimPathStart] == 0) {
14527f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathStart = a.getFloat(
14537f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
14547f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
14557f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
14567f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            // TODO: Consider replacing this with existing state attributes.
14579453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int[] states = {
14589453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    R.styleable.VectorDrawablePath_state_activated,
1459abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_checkable,
1460abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_checked,
1461abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_enabled,
1462abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_focused,
1463abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_hovered,
1464abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_pressed,
1465abb7d134c02ac60091108c491dafb00877093170John Hoford                    R.styleable.VectorDrawablePath_state_selected,
14669453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    R.styleable.VectorDrawablePath_state_window_focused
14679453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            };
14689453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14699453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int N = states.length;
14709453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            for (int i = 0; i < N; i++) {
14719453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final int state = states[i];
1472abb7d134c02ac60091108c491dafb00877093170John Hoford                if (a.hasValue(state)) {
1473abb7d134c02ac60091108c491dafb00877093170John Hoford                    addStateFilter(state, a.getBoolean(state, false));
1474abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1475abb7d134c02ac60091108c491dafb00877093170John Hoford            }
14769453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14779453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            updateColorAlphas();
14789453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1479abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
1480abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1481abb7d134c02ac60091108c491dafb00877093170John Hoford
14829453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean canApplyTheme() {
14839453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return mThemeAttrs != null;
14849453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
14859453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14869453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void applyTheme(Theme t) {
14879453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (mThemeAttrs == null) {
14889453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                return;
14899453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
14909453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14919453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final TypedArray a = t.resolveAttributes(
14929453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    mThemeAttrs, R.styleable.VectorDrawablePath, 0, 0);
14939453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14947f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
14959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
14967f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (a.hasValue(R.styleable.VectorDrawablePath_name)) {
14977f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mId = a.getString(R.styleable.VectorDrawablePath_name);
14989453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
14999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15007f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (a.hasValue(R.styleable.VectorDrawablePath_pathData)) {
15017f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData));
15029453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
15039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15047f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor);
15057f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity);
15067f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
15077f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mRotate = a.getFloat(R.styleable.VectorDrawablePath_rotation, mRotate);
15087f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mPivotX = a.getFloat(R.styleable.VectorDrawablePath_pivotX, mPivotX);
15097f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mPivotY = a.getFloat(R.styleable.VectorDrawablePath_pivotY, mPivotY);
15107f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
15117f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineCap = getStrokeLineCap(a.getInt(
15127f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
15137f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineJoin = getStrokeLineJoin(a.getInt(
15147f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
15157f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeMiterlimit = a.getFloat(
15167f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
15177f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor);
15187f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeOpacity = a.getFloat(
15197f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity);
15207f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth);
15217f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
15227f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd);
15237f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathOffset = a.getFloat(
15247f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
15257f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathStart = a.getFloat(
15267f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
15279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            updateColorAlphas();
15299453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
15309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private void updateColorAlphas() {
15329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (!Float.isNaN(mFillOpacity)) {
15339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mFillColor &= 0x00FFFFFF;
15349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mFillColor |= ((int) (0xFF * mFillOpacity)) << 24;
15359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
15369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
15379453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (!Float.isNaN(mStrokeOpacity)) {
15389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor &= 0x00FFFFFF;
15399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor |= ((int) (0xFF * mStrokeOpacity)) << 24;
15409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
15419453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
15429453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1543abb7d134c02ac60091108c491dafb00877093170John Hoford        private static int nextStart(String s, int end) {
1544abb7d134c02ac60091108c491dafb00877093170John Hoford            char c;
1545abb7d134c02ac60091108c491dafb00877093170John Hoford
1546abb7d134c02ac60091108c491dafb00877093170John Hoford            while (end < s.length()) {
1547abb7d134c02ac60091108c491dafb00877093170John Hoford                c = s.charAt(end);
1548abb7d134c02ac60091108c491dafb00877093170John Hoford                if (((c - 'A') * (c - 'Z') <= 0) || (((c - 'a') * (c - 'z') <= 0))) {
1549abb7d134c02ac60091108c491dafb00877093170John Hoford                    return end;
1550abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1551abb7d134c02ac60091108c491dafb00877093170John Hoford                end++;
1552abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1553abb7d134c02ac60091108c491dafb00877093170John Hoford            return end;
1554abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1555abb7d134c02ac60091108c491dafb00877093170John Hoford
1556abb7d134c02ac60091108c491dafb00877093170John Hoford        private void addNode(ArrayList<VectorDrawable.VNode> list, char cmd, float[] val) {
1557abb7d134c02ac60091108c491dafb00877093170John Hoford            list.add(new VectorDrawable.VNode(cmd, val));
1558abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1559abb7d134c02ac60091108c491dafb00877093170John Hoford
1560abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1561abb7d134c02ac60091108c491dafb00877093170John Hoford         * parse the floats in the string
1562abb7d134c02ac60091108c491dafb00877093170John Hoford         * this is an optimized version of
1563abb7d134c02ac60091108c491dafb00877093170John Hoford         * parseFloat(s.split(",|\\s"));
1564abb7d134c02ac60091108c491dafb00877093170John Hoford         *
1565abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param s the string containing a command and list of floats
1566abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return array of floats
1567abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1568abb7d134c02ac60091108c491dafb00877093170John Hoford        private static float[] getFloats(String s) {
1569abb7d134c02ac60091108c491dafb00877093170John Hoford            if (s.charAt(0) == 'z' | s.charAt(0) == 'Z') {
1570abb7d134c02ac60091108c491dafb00877093170John Hoford                return new float[0];
1571abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1572abb7d134c02ac60091108c491dafb00877093170John Hoford            try {
1573abb7d134c02ac60091108c491dafb00877093170John Hoford                float[] tmp = new float[s.length()];
1574abb7d134c02ac60091108c491dafb00877093170John Hoford                int count = 0;
1575abb7d134c02ac60091108c491dafb00877093170John Hoford                int pos = 1, end;
1576abb7d134c02ac60091108c491dafb00877093170John Hoford                while ((end = extract(s, pos)) >= 0) {
1577abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (pos < end) {
1578abb7d134c02ac60091108c491dafb00877093170John Hoford                        tmp[count++] = Float.parseFloat(s.substring(pos, end));
1579abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1580abb7d134c02ac60091108c491dafb00877093170John Hoford                    pos = end + 1;
1581abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1582abb7d134c02ac60091108c491dafb00877093170John Hoford                // handle the final float if there is one
1583abb7d134c02ac60091108c491dafb00877093170John Hoford                if (pos < s.length()) {
1584abb7d134c02ac60091108c491dafb00877093170John Hoford                    tmp[count++] = Float.parseFloat(s.substring(pos, s.length()));
1585abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1586abb7d134c02ac60091108c491dafb00877093170John Hoford                return Arrays.copyOf(tmp, count);
1587abb7d134c02ac60091108c491dafb00877093170John Hoford            } catch (NumberFormatException e){
1588abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.e(LOGTAG,"error in parsing \""+s+"\"");
1589abb7d134c02ac60091108c491dafb00877093170John Hoford                throw e;
1590abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1591abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1592abb7d134c02ac60091108c491dafb00877093170John Hoford
1593abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1594abb7d134c02ac60091108c491dafb00877093170John Hoford         * calculate the position of the next comma or space
1595abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param s the string to search
1596abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param start the position to start searching
1597abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return the position of the next comma or space or -1 if none found
1598abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1599abb7d134c02ac60091108c491dafb00877093170John Hoford        private static int extract(String s, int start) {
1600abb7d134c02ac60091108c491dafb00877093170John Hoford            int space = s.indexOf(' ', start);
1601abb7d134c02ac60091108c491dafb00877093170John Hoford            int comma = s.indexOf(',', start);
1602abb7d134c02ac60091108c491dafb00877093170John Hoford            if (space == -1) {
1603abb7d134c02ac60091108c491dafb00877093170John Hoford                return comma;
1604abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1605abb7d134c02ac60091108c491dafb00877093170John Hoford            if (comma == -1) {
1606abb7d134c02ac60091108c491dafb00877093170John Hoford                return space;
1607abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1608abb7d134c02ac60091108c491dafb00877093170John Hoford            return (comma > space) ? space : comma;
1609abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1610abb7d134c02ac60091108c491dafb00877093170John Hoford
1611abb7d134c02ac60091108c491dafb00877093170John Hoford        private VectorDrawable.VNode[] parsePath(String value) {
1612abb7d134c02ac60091108c491dafb00877093170John Hoford            int start = 0;
1613abb7d134c02ac60091108c491dafb00877093170John Hoford            int end = 1;
1614abb7d134c02ac60091108c491dafb00877093170John Hoford
1615abb7d134c02ac60091108c491dafb00877093170John Hoford            ArrayList<VectorDrawable.VNode> list = new ArrayList<VectorDrawable.VNode>();
1616abb7d134c02ac60091108c491dafb00877093170John Hoford            while (end < value.length()) {
1617abb7d134c02ac60091108c491dafb00877093170John Hoford                end = nextStart(value, end);
1618abb7d134c02ac60091108c491dafb00877093170John Hoford                String s = value.substring(start, end);
1619abb7d134c02ac60091108c491dafb00877093170John Hoford                float[] val = getFloats(s);
1620abb7d134c02ac60091108c491dafb00877093170John Hoford                addNode(list, s.charAt(0), val);
1621abb7d134c02ac60091108c491dafb00877093170John Hoford
1622abb7d134c02ac60091108c491dafb00877093170John Hoford                start = end;
1623abb7d134c02ac60091108c491dafb00877093170John Hoford                end++;
1624abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1625abb7d134c02ac60091108c491dafb00877093170John Hoford            if ((end - start) == 1 && start < value.length()) {
1626abb7d134c02ac60091108c491dafb00877093170John Hoford
1627abb7d134c02ac60091108c491dafb00877093170John Hoford                addNode(list, value.charAt(start), new float[0]);
1628abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1629abb7d134c02ac60091108c491dafb00877093170John Hoford            return list.toArray(new VectorDrawable.VNode[list.size()]);
1630abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1631abb7d134c02ac60091108c491dafb00877093170John Hoford
1632abb7d134c02ac60091108c491dafb00877093170John Hoford        public void copyFrom(VPath p1) {
1633abb7d134c02ac60091108c491dafb00877093170John Hoford            mNode = new VNode[p1.mNode.length];
1634abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mNode.length; i++) {
1635abb7d134c02ac60091108c491dafb00877093170John Hoford                mNode[i] = new VNode(p1.mNode[i]);
1636abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1637abb7d134c02ac60091108c491dafb00877093170John Hoford            mId = p1.mId;
1638abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokeColor = p1.mStrokeColor;
1639abb7d134c02ac60091108c491dafb00877093170John Hoford            mFillColor = p1.mFillColor;
1640abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokeWidth = p1.mStrokeWidth;
1641abb7d134c02ac60091108c491dafb00877093170John Hoford            mRotate = p1.mRotate;
1642abb7d134c02ac60091108c491dafb00877093170John Hoford            mPivotX = p1.mPivotX;
1643abb7d134c02ac60091108c491dafb00877093170John Hoford            mPivotY = p1.mPivotY;
1644abb7d134c02ac60091108c491dafb00877093170John Hoford            mAnimated = p1.mAnimated;
1645abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrimPathStart = p1.mTrimPathStart;
1646abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrimPathEnd = p1.mTrimPathEnd;
1647abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrimPathOffset = p1.mTrimPathOffset;
16487f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineCap = p1.mStrokeLineCap;
16497f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineJoin = p1.mStrokeLineJoin;
1650abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokeMiterlimit = p1.mStrokeMiterlimit;
1651abb7d134c02ac60091108c491dafb00877093170John Hoford            mNumberOfStates = p1.mNumberOfStates;
1652abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mNumberOfStates; i++) {
1653abb7d134c02ac60091108c491dafb00877093170John Hoford                mCheckState[i] = p1.mCheckState[i];
1654abb7d134c02ac60091108c491dafb00877093170John Hoford                mCheckValue[i] = p1.mCheckValue[i];
1655abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1656abb7d134c02ac60091108c491dafb00877093170John Hoford
1657abb7d134c02ac60091108c491dafb00877093170John Hoford            mFillRule = p1.mFillRule;
1658abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1659abb7d134c02ac60091108c491dafb00877093170John Hoford
1660abb7d134c02ac60091108c491dafb00877093170John Hoford        public static VPath interpolate(float t, VPath p1, VPath p2, VPath returnPath, int limit) {
1661abb7d134c02ac60091108c491dafb00877093170John Hoford            if (limit == LIMIT_ALL || limit == LIMIT_PATH) {
1662abb7d134c02ac60091108c491dafb00877093170John Hoford                if (returnPath.mNode == null || returnPath.mNode.length != p1.mNode.length) {
1663abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mNode = new VNode[p1.mNode.length];
1664abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1665abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int i = 0; i < returnPath.mNode.length; i++) {
1666abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (returnPath.mNode[i] == null) {
1667abb7d134c02ac60091108c491dafb00877093170John Hoford                        returnPath.mNode[i] = new VNode(p1.mNode[i], p2.mNode[i], t);
1668abb7d134c02ac60091108c491dafb00877093170John Hoford                    } else {
1669abb7d134c02ac60091108c491dafb00877093170John Hoford                        returnPath.mNode[i].interpolate(p1.mNode[i], p2.mNode[i], t);
1670abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1671abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1672abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1673abb7d134c02ac60091108c491dafb00877093170John Hoford            float t1 = 1 - t;
1674abb7d134c02ac60091108c491dafb00877093170John Hoford            switch (limit) {
1675abb7d134c02ac60091108c491dafb00877093170John Hoford                case LIMIT_ALL:
1676abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mRotate = t1 * p1.mRotate + t * p2.mRotate;
1677abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mPivotX = t1 * p1.mPivotX + t * p2.mPivotX;
1678abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mPivotY = t1 * p1.mPivotY + t * p2.mPivotY;
1679abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mClip = p1.mClip | p2.mClip;
1680abb7d134c02ac60091108c491dafb00877093170John Hoford
1681abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mTrimPathStart = t1 * p1.mTrimPathStart + t * p2.mTrimPathStart;
1682abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mTrimPathEnd = t1 * p1.mTrimPathEnd + t * p2.mTrimPathEnd;
1683abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mTrimPathOffset = t1 * p1.mTrimPathOffset + t * p2.mTrimPathOffset;
1684abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mStrokeMiterlimit =
1685abb7d134c02ac60091108c491dafb00877093170John Hoford                            t1 * p1.mStrokeMiterlimit + t * p2.mStrokeMiterlimit;
16867f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    returnPath.mStrokeLineCap = p1.mStrokeLineCap;
16877f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    if (returnPath.mStrokeLineCap == null) {
16887f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        returnPath.mStrokeLineCap = p2.mStrokeLineCap;
1689abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
16907f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    returnPath.mStrokeLineJoin = p1.mStrokeLineJoin;
16917f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    if (returnPath.mStrokeLineJoin == null) {
16927f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        returnPath.mStrokeLineJoin = p2.mStrokeLineJoin;
1693abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1694abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mFillRule = p1.mFillRule;
1695abb7d134c02ac60091108c491dafb00877093170John Hoford
1696abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mStrokeColor = rgbInterpolate(t, p1.mStrokeColor, p2.mStrokeColor);
1697abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mFillColor = rgbInterpolate(t, p1.mFillColor, p2.mFillColor);
1698abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mStrokeWidth = t1 * p1.mStrokeWidth + t * p2.mStrokeWidth;
1699abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mNumberOfStates = p1.mNumberOfStates;
1700abb7d134c02ac60091108c491dafb00877093170John Hoford                    for (int i = 0; i < returnPath.mNumberOfStates; i++) {
1701abb7d134c02ac60091108c491dafb00877093170John Hoford                        returnPath.mCheckState[i] = p1.mCheckState[i];
1702abb7d134c02ac60091108c491dafb00877093170John Hoford                        returnPath.mCheckValue[i] = p1.mCheckValue[i];
1703abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1704abb7d134c02ac60091108c491dafb00877093170John Hoford                    for (int i = 0; i < p2.mNumberOfStates; i++) {
1705abb7d134c02ac60091108c491dafb00877093170John Hoford                        returnPath.addStateFilter(p2.mCheckState[i], p2.mCheckValue[i]);
1706abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1707abb7d134c02ac60091108c491dafb00877093170John Hoford
1708abb7d134c02ac60091108c491dafb00877093170John Hoford                    int count = 0;
1709abb7d134c02ac60091108c491dafb00877093170John Hoford                    for (int i = 0; i < returnPath.mNumberOfStates; i++) {
1710abb7d134c02ac60091108c491dafb00877093170John Hoford                        if (returnPath.mCheckValue[i]) {
1711abb7d134c02ac60091108c491dafb00877093170John Hoford                            count++;
1712abb7d134c02ac60091108c491dafb00877093170John Hoford                        }
1713abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1714abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mNumberOfTrue = count;
1715abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1716abb7d134c02ac60091108c491dafb00877093170John Hoford                case LIMIT_ROTATE:
1717abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mRotate = t1 * p1.mRotate + t * p2.mRotate;
1718abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1719abb7d134c02ac60091108c491dafb00877093170John Hoford                case LIMIT_TRIM_PATH_END:
1720abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mTrimPathEnd = t1 * p1.mTrimPathEnd + t * p2.mTrimPathEnd;
1721abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1722abb7d134c02ac60091108c491dafb00877093170John Hoford                case LIMIT_TRIM_PATH_OFFSET:
1723abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mTrimPathOffset = t1 * p1.mTrimPathOffset + t * p2.mTrimPathOffset;
1724abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1725abb7d134c02ac60091108c491dafb00877093170John Hoford                case LIMIT_TRIM_PATH_START:
1726abb7d134c02ac60091108c491dafb00877093170John Hoford                    returnPath.mTrimPathStart = t1 * p1.mTrimPathStart + t * p2.mTrimPathStart;
1727abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1728abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1729abb7d134c02ac60091108c491dafb00877093170John Hoford            return returnPath;
1730abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1731abb7d134c02ac60091108c491dafb00877093170John Hoford
17324b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private static int rgbInterpolate(float fraction, int startColor, int endColor) {
17334b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            if (startColor == endColor) {
17344b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                return startColor;
17354b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            } else if (startColor == 0) {
17364b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                return endColor;
17374b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            } else if (endColor == 0) {
17384b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                return startColor;
1739abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1740abb7d134c02ac60091108c491dafb00877093170John Hoford
17414b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final int startA = (startColor >> 24) & 0xff;
17424b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final int startR = (startColor >> 16) & 0xff;
17434b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final int startG = (startColor >> 8) & 0xff;
17444b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final int startB = startColor & 0xff;
17454b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
17464b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final int endA = (endColor >> 24) & 0xff;
17474b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final int endR = (endColor >> 16) & 0xff;
17484b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final int endG = (endColor >> 8) & 0xff;
17494b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final int endB = endColor & 0xff;
17504b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
17514b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            return ((startA + (int)(fraction * (endA - startA))) << 24) |
17524b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    ((startR + (int)(fraction * (endR - startR))) << 16) |
17534b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    ((startG + (int)(fraction * (endG - startG))) << 8) |
17544b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    ((startB + (int)(fraction * (endB - startB))));
1755abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1756abb7d134c02ac60091108c491dafb00877093170John Hoford
1757abb7d134c02ac60091108c491dafb00877093170John Hoford        public boolean isVisible(int[] state) {
1758abb7d134c02ac60091108c491dafb00877093170John Hoford            int match = 0;
1759abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < state.length; i++) {
1760abb7d134c02ac60091108c491dafb00877093170John Hoford                int v = getState(state[i]);
1761abb7d134c02ac60091108c491dafb00877093170John Hoford                if (v != STATE_UNDEFINED) {
1762abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (v==STATE_TRUE) {
1763abb7d134c02ac60091108c491dafb00877093170John Hoford                        match++;
1764abb7d134c02ac60091108c491dafb00877093170John Hoford                    } else {
1765abb7d134c02ac60091108c491dafb00877093170John Hoford                        return false;
1766abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1767abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1768abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1769abb7d134c02ac60091108c491dafb00877093170John Hoford            return match == mNumberOfTrue;
1770abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1771abb7d134c02ac60091108c491dafb00877093170John Hoford    }
1772abb7d134c02ac60091108c491dafb00877093170John Hoford
1773abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VNode {
17745c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private char mType;
17755c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private float[] mParams;
17769453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1777abb7d134c02ac60091108c491dafb00877093170John Hoford        public VNode(char type, float[] params) {
17785c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mType = type;
17795c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mParams = params;
1780abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1781abb7d134c02ac60091108c491dafb00877093170John Hoford
1782abb7d134c02ac60091108c491dafb00877093170John Hoford        public VNode(VNode n) {
17835c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mType = n.mType;
17845c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mParams = Arrays.copyOf(n.mParams, n.mParams.length);
1785abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1786abb7d134c02ac60091108c491dafb00877093170John Hoford
1787abb7d134c02ac60091108c491dafb00877093170John Hoford        public VNode(VNode n1, VNode n2, float t) {
17885c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mType = n1.mType;
17895c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mParams = new float[n1.mParams.length];
1790abb7d134c02ac60091108c491dafb00877093170John Hoford            interpolate(n1, n2, t);
1791abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1792abb7d134c02ac60091108c491dafb00877093170John Hoford
1793abb7d134c02ac60091108c491dafb00877093170John Hoford        private boolean match(VNode n) {
17945c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            if (n.mType != mType) {
1795abb7d134c02ac60091108c491dafb00877093170John Hoford                return false;
1796abb7d134c02ac60091108c491dafb00877093170John Hoford            }
17975c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return (mParams.length == n.mParams.length);
1798abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1799abb7d134c02ac60091108c491dafb00877093170John Hoford
1800abb7d134c02ac60091108c491dafb00877093170John Hoford        public void interpolate(VNode n1, VNode n2, float t) {
18015c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            for (int i = 0; i < n1.mParams.length; i++) {
18025c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mParams[i] = n1.mParams[i] * (1 - t) + n2.mParams[i] * t;
1803abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1804abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1805abb7d134c02ac60091108c491dafb00877093170John Hoford
1806abb7d134c02ac60091108c491dafb00877093170John Hoford        private void nodeListToPath(VNode[] node, Path path) {
1807abb7d134c02ac60091108c491dafb00877093170John Hoford            float[] current = new float[4];
1808abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < node.length; i++) {
18095c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                addCommand(path, current, node[i].mType, node[i].mParams);
1810abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1811abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1812abb7d134c02ac60091108c491dafb00877093170John Hoford
1813abb7d134c02ac60091108c491dafb00877093170John Hoford        public static void createPath(VNode[] node, Path path) {
18145c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            float[] current = new float[4];
1815abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < node.length; i++) {
18165c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                addCommand(path, current, node[i].mType, node[i].mParams);
1817abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1818abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1819abb7d134c02ac60091108c491dafb00877093170John Hoford
1820abb7d134c02ac60091108c491dafb00877093170John Hoford        private static void addCommand(Path path, float[] current, char cmd, float[] val) {
1821abb7d134c02ac60091108c491dafb00877093170John Hoford
1822abb7d134c02ac60091108c491dafb00877093170John Hoford            int incr = 2;
1823abb7d134c02ac60091108c491dafb00877093170John Hoford            float currentX = current[0];
1824abb7d134c02ac60091108c491dafb00877093170John Hoford            float currentY = current[1];
1825abb7d134c02ac60091108c491dafb00877093170John Hoford            float ctrlPointX = current[2];
1826abb7d134c02ac60091108c491dafb00877093170John Hoford            float ctrlPointY = current[3];
1827abb7d134c02ac60091108c491dafb00877093170John Hoford
1828abb7d134c02ac60091108c491dafb00877093170John Hoford            switch (cmd) {
1829abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'z':
1830abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'Z':
1831abb7d134c02ac60091108c491dafb00877093170John Hoford                    path.close();
1832abb7d134c02ac60091108c491dafb00877093170John Hoford                    return;
1833abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'm':
1834abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'M':
1835abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'l':
1836abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'L':
1837abb7d134c02ac60091108c491dafb00877093170John Hoford                case 't':
1838abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'T':
1839abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 2;
1840abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1841abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'h':
1842abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'H':
1843abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'v':
1844abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'V':
1845abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 1;
1846abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1847abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'c':
1848abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'C':
1849abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 6;
1850abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1851abb7d134c02ac60091108c491dafb00877093170John Hoford                case 's':
1852abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'S':
1853abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'q':
1854abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'Q':
1855abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 4;
1856abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1857abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'a':
1858abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'A':
1859abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 7;
1860abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1861abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1862abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int k = 0; k < val.length; k += incr) {
1863abb7d134c02ac60091108c491dafb00877093170John Hoford                // TODO: build test to prove all permutations work
1864abb7d134c02ac60091108c491dafb00877093170John Hoford                switch (cmd) {
1865abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'm': // moveto - Start a new sub-path (relative)
1866abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rMoveTo(val[k + 0], val[k + 1]);
1867abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1868abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1869abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1870abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'M': // moveto - Start a new sub-path
1871abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.moveTo(val[k + 0], val[k + 1]);
1872abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1873abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 1];
1874abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1875abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'l': // lineto - Draw a line from the current point (relative)
1876abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(val[k + 0], val[k + 1]);
1877abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1878abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1879abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1880abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'L': // lineto - Draw a line from the current point
1881abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(val[k + 0], val[k + 1]);
1882abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1883abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 1];
1884abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1885abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'z': // closepath - Close the current subpath
1886abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'Z': // closepath - Close the current subpath
1887abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.close();
1888abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1889abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'h': // horizontal lineto - Draws a horizontal line (relative)
1890abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(val[k + 0], 0);
1891abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1892abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1893abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'H': // horizontal lineto - Draws a horizontal line
1894abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(val[k + 0], currentY);
1895abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1896abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1897abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'v': // vertical lineto - Draws a vertical line from the current point (r)
1898abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(0, val[k + 0]);
1899abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 0];
1900abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1901abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'V': // vertical lineto - Draws a vertical line from the current point
1902abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(currentX, val[k + 0]);
1903abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 0];
1904abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1905abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'c': // curveto - Draws a cubic Bézier curve (relative)
1906abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rCubicTo(val[k + 0],
1907abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
1908abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
1909abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3],
1910abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 4],
1911abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 5]);
1912abb7d134c02ac60091108c491dafb00877093170John Hoford
1913abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX + val[k + 2];
1914abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY + val[k + 3];
1915abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 4];
1916abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 5];
1917abb7d134c02ac60091108c491dafb00877093170John Hoford
1918abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1919abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'C': // curveto - Draws a cubic Bézier curve
1920abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.cubicTo(val[k + 0],
1921abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
1922abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
1923abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3],
1924abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 4],
1925abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 5]);
1926abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 4];
1927abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 5];
1928abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 2];
1929abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 3];
1930abb7d134c02ac60091108c491dafb00877093170John Hoford
1931abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1932abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp)
1933abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rCubicTo(currentX - ctrlPointX, currentY  - ctrlPointY,
1934abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1],
1935abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2], val[k + 3]);
1936abb7d134c02ac60091108c491dafb00877093170John Hoford
1937abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX + val[k + 0];
1938abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY + val[k + 1];
1939abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 2];
1940abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 3];
1941abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1942abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp)
1943abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.cubicTo(2 * currentX - ctrlPointX,
1944abb7d134c02ac60091108c491dafb00877093170John Hoford                                2 * currentY - ctrlPointY,
1945abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0],
1946abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
1947abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
1948abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3]);
1949abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 2];
1950abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 3];
1951abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 0];
1952abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 1];
1953abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1954abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'q': // Draws a quadratic Bézier (relative)
1955abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
1956abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 2];
1957abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 3];
1958abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 0];
1959abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 1];
1960abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1961abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'Q': // Draws a quadratic Bézier
1962abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
1963abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 2];
1964abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 3];
1965abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 0];
1966abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 1];
1967abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1968abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 't': // Draws a quadratic Bézier curve(reflective control point)(relative)
1969abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rQuadTo(currentX - ctrlPointX, currentY - ctrlPointY,
1970abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1]);
1971abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = ctrlPointX + currentX;
1972abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = ctrlPointY + currentY;
1973abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1974abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1975abb7d134c02ac60091108c491dafb00877093170John Hoford
1976abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1977abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'T': // Draws a quadratic Bézier curve (reflective control point)
1978abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.quadTo(currentX * 2 - ctrlPointX, currentY * 2 - ctrlPointY,
1979abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1]);
1980abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1981abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 1]; // TODO: Check this logic
1982abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = -(val[k + 0] - currentX);
1983abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = -(val[k + 1] - currentY);
1984abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1985abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'a': // Draws an elliptical arc
1986abb7d134c02ac60091108c491dafb00877093170John Hoford                        // (rx ry x-axis-rotation large-arc-flag sweep-flag x y)
1987abb7d134c02ac60091108c491dafb00877093170John Hoford                        drawArc(path,
1988abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentX,
1989abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentY,
1990abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 5] + currentX,
1991abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 6] + currentY,
1992abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0],
1993abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
1994abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
1995abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3] != 0,
1996abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 4] != 0);
1997abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 5];
1998abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 6];
1999abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX;
2000abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY;
2001abb7d134c02ac60091108c491dafb00877093170John Hoford
2002abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
2003abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'A': // Draws an elliptical arc
2004abb7d134c02ac60091108c491dafb00877093170John Hoford                        drawArc(path,
2005abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentX,
2006abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentY,
2007abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 5],
2008abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 6],
2009abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0],
2010abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
2011abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
2012abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3] != 0,
2013abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 4] != 0);
2014abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 5];
2015abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 6];
2016abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX;
2017abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY;
2018abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
2019abb7d134c02ac60091108c491dafb00877093170John Hoford                }
2020abb7d134c02ac60091108c491dafb00877093170John Hoford            }
2021abb7d134c02ac60091108c491dafb00877093170John Hoford            current[0] = currentX;
2022abb7d134c02ac60091108c491dafb00877093170John Hoford            current[1] = currentY;
2023abb7d134c02ac60091108c491dafb00877093170John Hoford            current[2] = ctrlPointX;
2024abb7d134c02ac60091108c491dafb00877093170John Hoford            current[3] = ctrlPointY;
2025abb7d134c02ac60091108c491dafb00877093170John Hoford        }
2026abb7d134c02ac60091108c491dafb00877093170John Hoford
2027abb7d134c02ac60091108c491dafb00877093170John Hoford        private static void drawArc(Path p,
2028abb7d134c02ac60091108c491dafb00877093170John Hoford                float x0,
2029abb7d134c02ac60091108c491dafb00877093170John Hoford                float y0,
2030abb7d134c02ac60091108c491dafb00877093170John Hoford                float x1,
2031abb7d134c02ac60091108c491dafb00877093170John Hoford                float y1,
2032abb7d134c02ac60091108c491dafb00877093170John Hoford                float a,
2033abb7d134c02ac60091108c491dafb00877093170John Hoford                float b,
2034abb7d134c02ac60091108c491dafb00877093170John Hoford                float theta,
2035abb7d134c02ac60091108c491dafb00877093170John Hoford                boolean isMoreThanHalf,
2036abb7d134c02ac60091108c491dafb00877093170John Hoford                boolean isPositiveArc) {
2037abb7d134c02ac60091108c491dafb00877093170John Hoford
2038abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Convert rotation angle from degrees to radians */
2039abb7d134c02ac60091108c491dafb00877093170John Hoford            double thetaD = Math.toRadians(theta);
2040abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Pre-compute rotation matrix entries */
2041abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosTheta = Math.cos(thetaD);
2042abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinTheta = Math.sin(thetaD);
2043abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Transform (x0, y0) and (x1, y1) into unit space */
2044abb7d134c02ac60091108c491dafb00877093170John Hoford            /* using (inverse) rotation, followed by (inverse) scale */
2045abb7d134c02ac60091108c491dafb00877093170John Hoford            double x0p = (x0 * cosTheta + y0 * sinTheta) / a;
2046abb7d134c02ac60091108c491dafb00877093170John Hoford            double y0p = (-x0 * sinTheta + y0 * cosTheta) / b;
2047abb7d134c02ac60091108c491dafb00877093170John Hoford            double x1p = (x1 * cosTheta + y1 * sinTheta) / a;
2048abb7d134c02ac60091108c491dafb00877093170John Hoford            double y1p = (-x1 * sinTheta + y1 * cosTheta) / b;
2049abb7d134c02ac60091108c491dafb00877093170John Hoford
2050abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Compute differences and averages */
2051abb7d134c02ac60091108c491dafb00877093170John Hoford            double dx = x0p - x1p;
2052abb7d134c02ac60091108c491dafb00877093170John Hoford            double dy = y0p - y1p;
2053abb7d134c02ac60091108c491dafb00877093170John Hoford            double xm = (x0p + x1p) / 2;
2054abb7d134c02ac60091108c491dafb00877093170John Hoford            double ym = (y0p + y1p) / 2;
2055abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Solve for intersecting unit circles */
2056abb7d134c02ac60091108c491dafb00877093170John Hoford            double dsq = dx * dx + dy * dy;
2057abb7d134c02ac60091108c491dafb00877093170John Hoford            if (dsq == 0.0) {
2058abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.w(LOGTAG, " Points are coincident");
2059abb7d134c02ac60091108c491dafb00877093170John Hoford                return; /* Points are coincident */
2060abb7d134c02ac60091108c491dafb00877093170John Hoford            }
2061abb7d134c02ac60091108c491dafb00877093170John Hoford            double disc = 1.0 / dsq - 1.0 / 4.0;
2062abb7d134c02ac60091108c491dafb00877093170John Hoford            if (disc < 0.0) {
2063abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.w(LOGTAG, "Points are too far apart " + dsq);
2064abb7d134c02ac60091108c491dafb00877093170John Hoford                float adjust = (float) (Math.sqrt(dsq) / 1.99999);
2065abb7d134c02ac60091108c491dafb00877093170John Hoford                drawArc(p, x0, y0, x1, y1, a * adjust,
2066abb7d134c02ac60091108c491dafb00877093170John Hoford                        b * adjust, theta, isMoreThanHalf, isPositiveArc);
2067abb7d134c02ac60091108c491dafb00877093170John Hoford                return; /* Points are too far apart */
2068abb7d134c02ac60091108c491dafb00877093170John Hoford            }
2069abb7d134c02ac60091108c491dafb00877093170John Hoford            double s = Math.sqrt(disc);
2070abb7d134c02ac60091108c491dafb00877093170John Hoford            double sdx = s * dx;
2071abb7d134c02ac60091108c491dafb00877093170John Hoford            double sdy = s * dy;
2072abb7d134c02ac60091108c491dafb00877093170John Hoford            double cx;
2073abb7d134c02ac60091108c491dafb00877093170John Hoford            double cy;
2074abb7d134c02ac60091108c491dafb00877093170John Hoford            if (isMoreThanHalf == isPositiveArc) {
2075abb7d134c02ac60091108c491dafb00877093170John Hoford                cx = xm - sdy;
2076abb7d134c02ac60091108c491dafb00877093170John Hoford                cy = ym + sdx;
2077abb7d134c02ac60091108c491dafb00877093170John Hoford            } else {
2078abb7d134c02ac60091108c491dafb00877093170John Hoford                cx = xm + sdy;
2079abb7d134c02ac60091108c491dafb00877093170John Hoford                cy = ym - sdx;
2080abb7d134c02ac60091108c491dafb00877093170John Hoford            }
2081abb7d134c02ac60091108c491dafb00877093170John Hoford
2082abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta0 = Math.atan2((y0p - cy), (x0p - cx));
2083abb7d134c02ac60091108c491dafb00877093170John Hoford
2084abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta1 = Math.atan2((y1p - cy), (x1p - cx));
2085abb7d134c02ac60091108c491dafb00877093170John Hoford
2086abb7d134c02ac60091108c491dafb00877093170John Hoford            double sweep = (eta1 - eta0);
2087abb7d134c02ac60091108c491dafb00877093170John Hoford            if (isPositiveArc != (sweep >= 0)) {
2088abb7d134c02ac60091108c491dafb00877093170John Hoford                if (sweep > 0) {
2089abb7d134c02ac60091108c491dafb00877093170John Hoford                    sweep -= 2 * Math.PI;
2090abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
2091abb7d134c02ac60091108c491dafb00877093170John Hoford                    sweep += 2 * Math.PI;
2092abb7d134c02ac60091108c491dafb00877093170John Hoford                }
2093abb7d134c02ac60091108c491dafb00877093170John Hoford            }
2094abb7d134c02ac60091108c491dafb00877093170John Hoford
2095abb7d134c02ac60091108c491dafb00877093170John Hoford            cx *= a;
2096abb7d134c02ac60091108c491dafb00877093170John Hoford            cy *= b;
2097abb7d134c02ac60091108c491dafb00877093170John Hoford            double tcx = cx;
2098abb7d134c02ac60091108c491dafb00877093170John Hoford            cx = cx * cosTheta - cy * sinTheta;
2099abb7d134c02ac60091108c491dafb00877093170John Hoford            cy = tcx * sinTheta + cy * cosTheta;
2100abb7d134c02ac60091108c491dafb00877093170John Hoford
2101abb7d134c02ac60091108c491dafb00877093170John Hoford            arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep);
2102abb7d134c02ac60091108c491dafb00877093170John Hoford        }
2103abb7d134c02ac60091108c491dafb00877093170John Hoford
2104abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
2105abb7d134c02ac60091108c491dafb00877093170John Hoford         * Converts an arc to cubic Bezier segments and records them in p.
2106abb7d134c02ac60091108c491dafb00877093170John Hoford         *
2107abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param p The target for the cubic Bezier segments
2108abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param cx The x coordinate center of the ellipse
2109abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param cy The y coordinate center of the ellipse
2110abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param a The radius of the ellipse in the horizontal direction
2111abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param b The radius of the ellipse in the vertical direction
2112abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param e1x E(eta1) x coordinate of the starting point of the arc
2113abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param e1y E(eta2) y coordinate of the starting point of the arc
2114abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param theta The angle that the ellipse bounding rectangle makes with horizontal plane
2115abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param start The start angle of the arc on the ellipse
2116abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse
2117abb7d134c02ac60091108c491dafb00877093170John Hoford         */
2118abb7d134c02ac60091108c491dafb00877093170John Hoford        private static void arcToBezier(Path p,
2119abb7d134c02ac60091108c491dafb00877093170John Hoford                double cx,
2120abb7d134c02ac60091108c491dafb00877093170John Hoford                double cy,
2121abb7d134c02ac60091108c491dafb00877093170John Hoford                double a,
2122abb7d134c02ac60091108c491dafb00877093170John Hoford                double b,
2123abb7d134c02ac60091108c491dafb00877093170John Hoford                double e1x,
2124abb7d134c02ac60091108c491dafb00877093170John Hoford                double e1y,
2125abb7d134c02ac60091108c491dafb00877093170John Hoford                double theta,
2126abb7d134c02ac60091108c491dafb00877093170John Hoford                double start,
2127abb7d134c02ac60091108c491dafb00877093170John Hoford                double sweep) {
2128abb7d134c02ac60091108c491dafb00877093170John Hoford            // Taken from equations at: http://spaceroots.org/documents/ellipse/node8.html
2129abb7d134c02ac60091108c491dafb00877093170John Hoford            // and http://www.spaceroots.org/documents/ellipse/node22.html
2130abb7d134c02ac60091108c491dafb00877093170John Hoford
2131abb7d134c02ac60091108c491dafb00877093170John Hoford            // Maximum of 45 degrees per cubic Bezier segment
2132abb7d134c02ac60091108c491dafb00877093170John Hoford            int numSegments = Math.abs((int) Math.ceil(sweep * 4 / Math.PI));
2133abb7d134c02ac60091108c491dafb00877093170John Hoford
2134abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta1 = start;
2135abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosTheta = Math.cos(theta);
2136abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinTheta = Math.sin(theta);
2137abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosEta1 = Math.cos(eta1);
2138abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinEta1 = Math.sin(eta1);
2139abb7d134c02ac60091108c491dafb00877093170John Hoford            double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1);
2140abb7d134c02ac60091108c491dafb00877093170John Hoford            double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1);
2141abb7d134c02ac60091108c491dafb00877093170John Hoford
2142abb7d134c02ac60091108c491dafb00877093170John Hoford            double anglePerSegment = sweep / numSegments;
2143abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < numSegments; i++) {
2144abb7d134c02ac60091108c491dafb00877093170John Hoford                double eta2 = eta1 + anglePerSegment;
2145abb7d134c02ac60091108c491dafb00877093170John Hoford                double sinEta2 = Math.sin(eta2);
2146abb7d134c02ac60091108c491dafb00877093170John Hoford                double cosEta2 = Math.cos(eta2);
2147abb7d134c02ac60091108c491dafb00877093170John Hoford                double e2x = cx + (a * cosTheta * cosEta2) - (b * sinTheta * sinEta2);
2148abb7d134c02ac60091108c491dafb00877093170John Hoford                double e2y = cy + (a * sinTheta * cosEta2) + (b * cosTheta * sinEta2);
2149abb7d134c02ac60091108c491dafb00877093170John Hoford                double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2;
2150abb7d134c02ac60091108c491dafb00877093170John Hoford                double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2;
2151abb7d134c02ac60091108c491dafb00877093170John Hoford                double tanDiff2 = Math.tan((eta2 - eta1) / 2);
2152abb7d134c02ac60091108c491dafb00877093170John Hoford                double alpha =
2153abb7d134c02ac60091108c491dafb00877093170John Hoford                        Math.sin(eta2 - eta1) * (Math.sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3;
2154abb7d134c02ac60091108c491dafb00877093170John Hoford                double q1x = e1x + alpha * ep1x;
2155abb7d134c02ac60091108c491dafb00877093170John Hoford                double q1y = e1y + alpha * ep1y;
2156abb7d134c02ac60091108c491dafb00877093170John Hoford                double q2x = e2x - alpha * ep2x;
2157abb7d134c02ac60091108c491dafb00877093170John Hoford                double q2y = e2y - alpha * ep2y;
2158abb7d134c02ac60091108c491dafb00877093170John Hoford
2159abb7d134c02ac60091108c491dafb00877093170John Hoford                p.cubicTo((float) q1x,
2160abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q1y,
2161abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q2x,
2162abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q2y,
2163abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) e2x,
2164abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) e2y);
2165abb7d134c02ac60091108c491dafb00877093170John Hoford                eta1 = eta2;
2166abb7d134c02ac60091108c491dafb00877093170John Hoford                e1x = e2x;
2167abb7d134c02ac60091108c491dafb00877093170John Hoford                e1y = e2y;
2168abb7d134c02ac60091108c491dafb00877093170John Hoford                ep1x = ep2x;
2169abb7d134c02ac60091108c491dafb00877093170John Hoford                ep1y = ep2y;
2170abb7d134c02ac60091108c491dafb00877093170John Hoford            }
2171abb7d134c02ac60091108c491dafb00877093170John Hoford        }
2172abb7d134c02ac60091108c491dafb00877093170John Hoford
2173abb7d134c02ac60091108c491dafb00877093170John Hoford    }
2174abb7d134c02ac60091108c491dafb00877093170John Hoford}
2175