AnimatorInflater.java revision 9032fa5808d7808f54d31d646049d0b1f4a9491b
1d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase/*
2d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * Copyright (C) 2010 The Android Open Source Project
3d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase *
4d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * Licensed under the Apache License, Version 2.0 (the "License");
5d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * you may not use this file except in compliance with the License.
6d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * You may obtain a copy of the License at
7d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase *
8d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase *      http://www.apache.org/licenses/LICENSE-2.0
9d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase *
10d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * Unless required by applicable law or agreed to in writing, software
11d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * distributed under the License is distributed on an "AS IS" BASIS,
12d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * See the License for the specific language governing permissions and
14d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * limitations under the License.
15d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase */
16d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haasepackage android.animation;
17d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase
187b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbyeimport android.annotation.AnimatorRes;
19d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.content.Context;
20d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyarimport android.content.res.ConfigurationBoundResourceCache;
21d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyarimport android.content.res.ConstantState;
22d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.content.res.Resources;
23cf4832f69c8786b098ce18c24319021f8cd6733aztenghuiimport android.content.res.Resources.NotFoundException;
24e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghuiimport android.content.res.Resources.Theme;
25d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.content.res.TypedArray;
26d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.content.res.XmlResourceParser;
27cf4832f69c8786b098ce18c24319021f8cd6733aztenghuiimport android.graphics.Path;
28d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.util.AttributeSet;
29eb034fbca40006c55db143047eb628c4b657730aztenghuiimport android.util.Log;
30cf4832f69c8786b098ce18c24319021f8cd6733aztenghuiimport android.util.PathParser;
31f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyarimport android.util.StateSet;
325bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haaseimport android.util.TypedValue;
33d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.util.Xml;
34eb034fbca40006c55db143047eb628c4b657730aztenghuiimport android.view.InflateException;
35d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.view.animation.AnimationUtils;
36d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyarimport android.view.animation.BaseInterpolator;
37d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyarimport android.view.animation.Interpolator;
38e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
39e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghuiimport com.android.internal.R;
40e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
41d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport org.xmlpull.v1.XmlPullParser;
42d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport org.xmlpull.v1.XmlPullParserException;
43d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase
44d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport java.io.IOException;
45d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport java.util.ArrayList;
46d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase
47d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase/**
486cfdf4538049e4b96f50d8c0fe3119664420cc34Chet Haase * This class is used to instantiate animator XML files into Animator objects.
49d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * <p>
506cfdf4538049e4b96f50d8c0fe3119664420cc34Chet Haase * For performance reasons, inflation relies heavily on pre-processing of
51d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * XML files that is done at build time. Therefore, it is not currently possible
526cfdf4538049e4b96f50d8c0fe3119664420cc34Chet Haase * to use this inflater with an XmlPullParser over a plain XML file at runtime;
53d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * it only works with an XmlPullParser returned from a compiled resource (R.
54d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * <em>something</em> file.)
55d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase */
56a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haasepublic class AnimatorInflater {
57eb034fbca40006c55db143047eb628c4b657730aztenghui    private static final String TAG = "AnimatorInflater";
58d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase    /**
59a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * These flags are used when parsing AnimatorSet objects
60d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase     */
61d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase    private static final int TOGETHER = 0;
62d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase    private static final int SEQUENTIALLY = 1;
63d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase
64d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase    /**
65d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase     * Enum values used in XML attributes to indicate the value for mValueType
66d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase     */
67d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase    private static final int VALUE_TYPE_FLOAT       = 0;
68d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase    private static final int VALUE_TYPE_INT         = 1;
69eb034fbca40006c55db143047eb628c4b657730aztenghui    private static final int VALUE_TYPE_PATH        = 2;
70d430753cba09acb07af8b313286f247c78a41a32Chet Haase    private static final int VALUE_TYPE_COLOR       = 3;
719032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu    private static final int VALUE_TYPE_UNDEFINED   = 4;
72d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase
73eb034fbca40006c55db143047eb628c4b657730aztenghui    private static final boolean DBG_ANIMATOR_INFLATER = false;
74eb034fbca40006c55db143047eb628c4b657730aztenghui
75d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar    // used to calculate changing configs for resource references
76d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar    private static final TypedValue sTmpTypedValue = new TypedValue();
77d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar
78d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase    /**
79a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Loads an {@link Animator} object from a resource
80d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase     *
81d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase     * @param context Application context used to access resources
82d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase     * @param id The resource id of the animation to load
83a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * @return The animator object reference by the specified id
84d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase     * @throws android.content.res.Resources.NotFoundException when the animation cannot be loaded
85d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase     */
867b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbye    public static Animator loadAnimator(Context context, @AnimatorRes int id)
87d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase            throws NotFoundException {
88e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        return loadAnimator(context.getResources(), context.getTheme(), id);
89e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    }
90e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
91e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    /**
92e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * Loads an {@link Animator} object from a resource
93e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     *
94e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * @param resources The resources
95e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * @param theme The theme
96e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * @param id The resource id of the animation to load
97e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * @return The animator object reference by the specified id
98e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * @throws android.content.res.Resources.NotFoundException when the animation cannot be loaded
99e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * @hide
100e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     */
101e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    public static Animator loadAnimator(Resources resources, Theme theme, int id)
102e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            throws NotFoundException {
103fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount        return loadAnimator(resources, theme, id, 1);
104fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount    }
105fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount
106fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount    /** @hide */
107fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount    public static Animator loadAnimator(Resources resources, Theme theme, int id,
108fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount            float pathErrorScale) throws NotFoundException {
109d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        final ConfigurationBoundResourceCache<Animator> animatorCache = resources
110d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                .getAnimatorCache();
111d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        Animator animator = animatorCache.get(id, theme);
112d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        if (animator != null) {
113d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            if (DBG_ANIMATOR_INFLATER) {
114d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                Log.d(TAG, "loaded animator from cache, " + resources.getResourceName(id));
115d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            }
116d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            return animator;
117d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        } else if (DBG_ANIMATOR_INFLATER) {
118d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            Log.d(TAG, "cache miss for animator " + resources.getResourceName(id));
119d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        }
120d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        XmlResourceParser parser = null;
121d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        try {
122e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            parser = resources.getAnimation(id);
123d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            animator = createAnimatorFromXml(resources, theme, parser, pathErrorScale);
124d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            if (animator != null) {
125d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                animator.appendChangingConfigurations(getChangingConfigs(resources, id));
126d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                final ConstantState<Animator> constantState = animator.createConstantState();
127d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                if (constantState != null) {
128d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                    if (DBG_ANIMATOR_INFLATER) {
129d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                        Log.d(TAG, "caching animator for res " + resources.getResourceName(id));
130d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                    }
131d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                    animatorCache.put(id, theme, constantState);
132d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                    // create a new animator so that cached version is never used by the user
133d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                    animator = constantState.newInstance(resources, theme);
134d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                }
135d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            }
136d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            return animator;
137d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        } catch (XmlPullParserException ex) {
138d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase            Resources.NotFoundException rnf =
139d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase                    new Resources.NotFoundException("Can't load animation resource ID #0x" +
140fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount                            Integer.toHexString(id));
141d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase            rnf.initCause(ex);
142d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase            throw rnf;
143d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        } catch (IOException ex) {
144d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase            Resources.NotFoundException rnf =
145d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase                    new Resources.NotFoundException("Can't load animation resource ID #0x" +
146fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount                            Integer.toHexString(id));
147d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase            rnf.initCause(ex);
148d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase            throw rnf;
149d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        } finally {
150d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase            if (parser != null) parser.close();
151d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        }
152d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase    }
153d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase
154f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar    public static StateListAnimator loadStateListAnimator(Context context, int id)
155f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            throws NotFoundException {
156d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        final Resources resources = context.getResources();
157d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        final ConfigurationBoundResourceCache<StateListAnimator> cache = resources
158d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                .getStateListAnimatorCache();
159d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        final Theme theme = context.getTheme();
160d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        StateListAnimator animator = cache.get(id, theme);
161d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        if (animator != null) {
162d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            return animator;
163d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        }
164f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        XmlResourceParser parser = null;
165f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        try {
166d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            parser = resources.getAnimation(id);
167d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            animator = createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser));
168d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            if (animator != null) {
169d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                animator.appendChangingConfigurations(getChangingConfigs(resources, id));
170d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                final ConstantState<StateListAnimator> constantState = animator
171d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                        .createConstantState();
172d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                if (constantState != null) {
173d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                    cache.put(id, theme, constantState);
174d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                    // return a clone so that the animator in constant state is never used.
175d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                    animator = constantState.newInstance(resources, theme);
176d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                }
177d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            }
178d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            return animator;
179f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        } catch (XmlPullParserException ex) {
180f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            Resources.NotFoundException rnf =
181f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    new Resources.NotFoundException(
182f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                            "Can't load state list animator resource ID #0x" +
183f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                                    Integer.toHexString(id)
184f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    );
185f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            rnf.initCause(ex);
186f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            throw rnf;
187f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        } catch (IOException ex) {
188f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            Resources.NotFoundException rnf =
189f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    new Resources.NotFoundException(
190f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                            "Can't load state list animator resource ID #0x" +
191f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                                    Integer.toHexString(id)
192f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    );
193f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            rnf.initCause(ex);
194f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            throw rnf;
195f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        } finally {
196f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            if (parser != null) {
197f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                parser.close();
198f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            }
199f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        }
200f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar    }
201f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar
202f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar    private static StateListAnimator createStateListAnimatorFromXml(Context context,
203f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            XmlPullParser parser, AttributeSet attributeSet)
204f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            throws IOException, XmlPullParserException {
205f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        int type;
206f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        StateListAnimator stateListAnimator = new StateListAnimator();
207f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar
208f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        while (true) {
209f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            type = parser.next();
210f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            switch (type) {
211f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                case XmlPullParser.END_DOCUMENT:
212f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                case XmlPullParser.END_TAG:
213f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    return stateListAnimator;
214f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar
215f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                case XmlPullParser.START_TAG:
216f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    // parse item
217f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    Animator animator = null;
218f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    if ("item".equals(parser.getName())) {
219f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        int attributeCount = parser.getAttributeCount();
220f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        int[] states = new int[attributeCount];
221f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        int stateIndex = 0;
222f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        for (int i = 0; i < attributeCount; i++) {
223f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                            int attrName = attributeSet.getAttributeNameResource(i);
224cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                            if (attrName == R.attr.animation) {
225d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                                final int animId = attributeSet.getAttributeResourceValue(i, 0);
226d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                                animator = loadAnimator(context, animId);
227f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                            } else {
228f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                                states[stateIndex++] =
229f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                                        attributeSet.getAttributeBooleanValue(i, false) ?
230f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                                                attrName : -attrName;
231f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                            }
232f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        }
233f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        if (animator == null) {
234e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                            animator = createAnimatorFromXml(context.getResources(),
235fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount                                    context.getTheme(), parser, 1f);
236f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        }
237f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar
238f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        if (animator == null) {
239f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                            throw new Resources.NotFoundException(
240f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                                    "animation state item must have a valid animation");
241f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        }
242f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        stateListAnimator
243f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                                .addState(StateSet.trimStateSet(states, stateIndex), animator);
244f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    }
245f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    break;
246f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            }
247f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        }
248f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar    }
249f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar
250cf4832f69c8786b098ce18c24319021f8cd6733aztenghui    /**
251eb034fbca40006c55db143047eb628c4b657730aztenghui     * PathDataEvaluator is used to interpolate between two paths which are
252eb034fbca40006c55db143047eb628c4b657730aztenghui     * represented in the same format but different control points' values.
253eb034fbca40006c55db143047eb628c4b657730aztenghui     * The path is represented as an array of PathDataNode here, which is
254eb034fbca40006c55db143047eb628c4b657730aztenghui     * fundamentally an array of floating point numbers.
255eb034fbca40006c55db143047eb628c4b657730aztenghui     */
256eb034fbca40006c55db143047eb628c4b657730aztenghui    private static class PathDataEvaluator implements TypeEvaluator<PathParser.PathDataNode[]> {
257eb034fbca40006c55db143047eb628c4b657730aztenghui        private PathParser.PathDataNode[] mNodeArray;
258eb034fbca40006c55db143047eb628c4b657730aztenghui
259eb034fbca40006c55db143047eb628c4b657730aztenghui        /**
260eb034fbca40006c55db143047eb628c4b657730aztenghui         * Create a PathParser.PathDataNode[] that does not reuse the animated value.
261eb034fbca40006c55db143047eb628c4b657730aztenghui         * Care must be taken when using this option because on every evaluation
262eb034fbca40006c55db143047eb628c4b657730aztenghui         * a new <code>PathParser.PathDataNode[]</code> will be allocated.
263eb034fbca40006c55db143047eb628c4b657730aztenghui         */
264eb034fbca40006c55db143047eb628c4b657730aztenghui        private PathDataEvaluator() {}
265eb034fbca40006c55db143047eb628c4b657730aztenghui
266eb034fbca40006c55db143047eb628c4b657730aztenghui        /**
267eb034fbca40006c55db143047eb628c4b657730aztenghui         * Create a PathDataEvaluator that reuses <code>nodeArray</code> for every evaluate() call.
268eb034fbca40006c55db143047eb628c4b657730aztenghui         * Caution must be taken to ensure that the value returned from
269eb034fbca40006c55db143047eb628c4b657730aztenghui         * {@link android.animation.ValueAnimator#getAnimatedValue()} is not cached, modified, or
270eb034fbca40006c55db143047eb628c4b657730aztenghui         * used across threads. The value will be modified on each <code>evaluate()</code> call.
271eb034fbca40006c55db143047eb628c4b657730aztenghui         *
272eb034fbca40006c55db143047eb628c4b657730aztenghui         * @param nodeArray The array to modify and return from <code>evaluate</code>.
273eb034fbca40006c55db143047eb628c4b657730aztenghui         */
274eb034fbca40006c55db143047eb628c4b657730aztenghui        public PathDataEvaluator(PathParser.PathDataNode[] nodeArray) {
275eb034fbca40006c55db143047eb628c4b657730aztenghui            mNodeArray = nodeArray;
276eb034fbca40006c55db143047eb628c4b657730aztenghui        }
277eb034fbca40006c55db143047eb628c4b657730aztenghui
278eb034fbca40006c55db143047eb628c4b657730aztenghui        @Override
279eb034fbca40006c55db143047eb628c4b657730aztenghui        public PathParser.PathDataNode[] evaluate(float fraction,
280eb034fbca40006c55db143047eb628c4b657730aztenghui                PathParser.PathDataNode[] startPathData,
281eb034fbca40006c55db143047eb628c4b657730aztenghui                PathParser.PathDataNode[] endPathData) {
282eb034fbca40006c55db143047eb628c4b657730aztenghui            if (!PathParser.canMorph(startPathData, endPathData)) {
283eb034fbca40006c55db143047eb628c4b657730aztenghui                throw new IllegalArgumentException("Can't interpolate between"
284eb034fbca40006c55db143047eb628c4b657730aztenghui                        + " two incompatible pathData");
285eb034fbca40006c55db143047eb628c4b657730aztenghui            }
286eb034fbca40006c55db143047eb628c4b657730aztenghui
287eb034fbca40006c55db143047eb628c4b657730aztenghui            if (mNodeArray == null || !PathParser.canMorph(mNodeArray, startPathData)) {
288eb034fbca40006c55db143047eb628c4b657730aztenghui                mNodeArray = PathParser.deepCopyNodes(startPathData);
289eb034fbca40006c55db143047eb628c4b657730aztenghui            }
290eb034fbca40006c55db143047eb628c4b657730aztenghui
291eb034fbca40006c55db143047eb628c4b657730aztenghui            for (int i = 0; i < startPathData.length; i++) {
292eb034fbca40006c55db143047eb628c4b657730aztenghui                mNodeArray[i].interpolatePathDataNode(startPathData[i],
293eb034fbca40006c55db143047eb628c4b657730aztenghui                        endPathData[i], fraction);
294eb034fbca40006c55db143047eb628c4b657730aztenghui            }
295eb034fbca40006c55db143047eb628c4b657730aztenghui
296eb034fbca40006c55db143047eb628c4b657730aztenghui            return mNodeArray;
297eb034fbca40006c55db143047eb628c4b657730aztenghui        }
298eb034fbca40006c55db143047eb628c4b657730aztenghui    }
299eb034fbca40006c55db143047eb628c4b657730aztenghui
300d430753cba09acb07af8b313286f247c78a41a32Chet Haase    private static PropertyValuesHolder getPVH(TypedArray styledAttributes, int valueType,
301d430753cba09acb07af8b313286f247c78a41a32Chet Haase            int valueFromId, int valueToId, String propertyName) {
3025bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase
303d430753cba09acb07af8b313286f247c78a41a32Chet Haase        TypedValue tvFrom = styledAttributes.peekValue(valueFromId);
3045bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase        boolean hasFrom = (tvFrom != null);
3055bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase        int fromType = hasFrom ? tvFrom.type : 0;
306d430753cba09acb07af8b313286f247c78a41a32Chet Haase        TypedValue tvTo = styledAttributes.peekValue(valueToId);
3075bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase        boolean hasTo = (tvTo != null);
3085bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase        int toType = hasTo ? tvTo.type : 0;
3095bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase
3109032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu        if (valueType == VALUE_TYPE_UNDEFINED) {
3119032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu            // Check whether it's color type. If not, fall back to default type (i.e. float type)
3129032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu            if ((hasFrom && isColorType(fromType)) || (hasTo && isColorType(toType))) {
3139032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu                valueType = VALUE_TYPE_COLOR;
3149032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu            } else {
3159032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu                valueType = VALUE_TYPE_FLOAT;
3169032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu            }
3179032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu        }
3189032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu
3199032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu        boolean getFloats = (valueType == VALUE_TYPE_FLOAT);
3209032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu
321d430753cba09acb07af8b313286f247c78a41a32Chet Haase        PropertyValuesHolder returnValue = null;
322d430753cba09acb07af8b313286f247c78a41a32Chet Haase
323eb034fbca40006c55db143047eb628c4b657730aztenghui        if (valueType == VALUE_TYPE_PATH) {
324d430753cba09acb07af8b313286f247c78a41a32Chet Haase            String fromString = styledAttributes.getString(valueFromId);
325d430753cba09acb07af8b313286f247c78a41a32Chet Haase            String toString = styledAttributes.getString(valueToId);
326d430753cba09acb07af8b313286f247c78a41a32Chet Haase            PathParser.PathDataNode[] nodesFrom = PathParser.createNodesFromPathData(fromString);
327d430753cba09acb07af8b313286f247c78a41a32Chet Haase            PathParser.PathDataNode[] nodesTo = PathParser.createNodesFromPathData(toString);
328d430753cba09acb07af8b313286f247c78a41a32Chet Haase
329d430753cba09acb07af8b313286f247c78a41a32Chet Haase            if (nodesFrom != null || nodesTo != null) {
330d430753cba09acb07af8b313286f247c78a41a32Chet Haase                if (nodesFrom != null) {
331d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    TypeEvaluator evaluator =
332d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            new PathDataEvaluator(PathParser.deepCopyNodes(nodesFrom));
333d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    if (nodesTo != null) {
334d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        if (!PathParser.canMorph(nodesFrom, nodesTo)) {
335d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            throw new InflateException(" Can't morph from " + fromString + " to " +
336d430753cba09acb07af8b313286f247c78a41a32Chet Haase                                    toString);
337d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        }
338d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        returnValue = PropertyValuesHolder.ofObject(propertyName, evaluator,
339d430753cba09acb07af8b313286f247c78a41a32Chet Haase                                nodesFrom, nodesTo);
340d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    } else {
341d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        returnValue = PropertyValuesHolder.ofObject(propertyName, evaluator,
342d430753cba09acb07af8b313286f247c78a41a32Chet Haase                                (Object) nodesFrom);
343d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    }
344d430753cba09acb07af8b313286f247c78a41a32Chet Haase                } else if (nodesTo != null) {
345d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    TypeEvaluator evaluator =
346d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            new PathDataEvaluator(PathParser.deepCopyNodes(nodesTo));
347d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    returnValue = PropertyValuesHolder.ofObject(propertyName, evaluator,
348d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            (Object) nodesTo);
349d430753cba09acb07af8b313286f247c78a41a32Chet Haase                }
350d430753cba09acb07af8b313286f247c78a41a32Chet Haase            }
351eb034fbca40006c55db143047eb628c4b657730aztenghui        } else {
352d430753cba09acb07af8b313286f247c78a41a32Chet Haase            TypeEvaluator evaluator = null;
353eb034fbca40006c55db143047eb628c4b657730aztenghui            // Integer and float value types are handled here.
3549032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu            if (valueType == VALUE_TYPE_COLOR) {
355eb034fbca40006c55db143047eb628c4b657730aztenghui                // special case for colors: ignore valueType and get ints
356eb034fbca40006c55db143047eb628c4b657730aztenghui                evaluator = ArgbEvaluator.getInstance();
357eb034fbca40006c55db143047eb628c4b657730aztenghui            }
358d430753cba09acb07af8b313286f247c78a41a32Chet Haase            if (getFloats) {
359d430753cba09acb07af8b313286f247c78a41a32Chet Haase                float valueFrom;
360d430753cba09acb07af8b313286f247c78a41a32Chet Haase                float valueTo;
361d430753cba09acb07af8b313286f247c78a41a32Chet Haase                if (hasFrom) {
362d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    if (fromType == TypedValue.TYPE_DIMENSION) {
363d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        valueFrom = styledAttributes.getDimension(valueFromId, 0f);
364d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    } else {
365d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        valueFrom = styledAttributes.getFloat(valueFromId, 0f);
366d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    }
367d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    if (hasTo) {
368d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        if (toType == TypedValue.TYPE_DIMENSION) {
369d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            valueTo = styledAttributes.getDimension(valueToId, 0f);
370d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        } else {
371d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            valueTo = styledAttributes.getFloat(valueToId, 0f);
372d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        }
373d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        returnValue = PropertyValuesHolder.ofFloat(propertyName,
374d430753cba09acb07af8b313286f247c78a41a32Chet Haase                                valueFrom, valueTo);
375d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    } else {
376d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        returnValue = PropertyValuesHolder.ofFloat(propertyName, valueFrom);
377d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    }
378d430753cba09acb07af8b313286f247c78a41a32Chet Haase                } else {
379d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    if (toType == TypedValue.TYPE_DIMENSION) {
380d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        valueTo = styledAttributes.getDimension(valueToId, 0f);
381d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    } else {
382d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        valueTo = styledAttributes.getFloat(valueToId, 0f);
383d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    }
384d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    returnValue = PropertyValuesHolder.ofFloat(propertyName, valueTo);
385d430753cba09acb07af8b313286f247c78a41a32Chet Haase                }
386d430753cba09acb07af8b313286f247c78a41a32Chet Haase            } else {
387d430753cba09acb07af8b313286f247c78a41a32Chet Haase                int valueFrom;
388d430753cba09acb07af8b313286f247c78a41a32Chet Haase                int valueTo;
389d430753cba09acb07af8b313286f247c78a41a32Chet Haase                if (hasFrom) {
390d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    if (fromType == TypedValue.TYPE_DIMENSION) {
391d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        valueFrom = (int) styledAttributes.getDimension(valueFromId, 0f);
3929032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu                    } else if (isColorType(fromType)) {
393d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        valueFrom = styledAttributes.getColor(valueFromId, 0);
394d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    } else {
395d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        valueFrom = styledAttributes.getInt(valueFromId, 0);
396d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    }
397d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    if (hasTo) {
398d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        if (toType == TypedValue.TYPE_DIMENSION) {
399d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            valueTo = (int) styledAttributes.getDimension(valueToId, 0f);
4009032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu                        } else if (isColorType(toType)) {
401d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            valueTo = styledAttributes.getColor(valueToId, 0);
402d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        } else {
403d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            valueTo = styledAttributes.getInt(valueToId, 0);
404d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        }
405d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        returnValue = PropertyValuesHolder.ofInt(propertyName, valueFrom, valueTo);
406d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    } else {
407d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        returnValue = PropertyValuesHolder.ofInt(propertyName, valueFrom);
408d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    }
409d430753cba09acb07af8b313286f247c78a41a32Chet Haase                } else {
410d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    if (hasTo) {
411d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        if (toType == TypedValue.TYPE_DIMENSION) {
412d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            valueTo = (int) styledAttributes.getDimension(valueToId, 0f);
4139032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu                        } else if (isColorType(toType)) {
414d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            valueTo = styledAttributes.getColor(valueToId, 0);
415d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        } else {
416d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            valueTo = styledAttributes.getInt(valueToId, 0);
417d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        }
418d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        returnValue = PropertyValuesHolder.ofInt(propertyName, valueTo);
419d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    }
420d430753cba09acb07af8b313286f247c78a41a32Chet Haase                }
421d430753cba09acb07af8b313286f247c78a41a32Chet Haase            }
422d430753cba09acb07af8b313286f247c78a41a32Chet Haase            if (returnValue != null && evaluator != null) {
423d430753cba09acb07af8b313286f247c78a41a32Chet Haase                returnValue.setEvaluator(evaluator);
424d430753cba09acb07af8b313286f247c78a41a32Chet Haase            }
425d430753cba09acb07af8b313286f247c78a41a32Chet Haase        }
426d430753cba09acb07af8b313286f247c78a41a32Chet Haase
427d430753cba09acb07af8b313286f247c78a41a32Chet Haase        return returnValue;
428d430753cba09acb07af8b313286f247c78a41a32Chet Haase    }
429d430753cba09acb07af8b313286f247c78a41a32Chet Haase
430d430753cba09acb07af8b313286f247c78a41a32Chet Haase    /**
431d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * @param anim The animator, must not be null
432d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * @param arrayAnimator Incoming typed array for Animator's attributes.
433d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * @param arrayObjectAnimator Incoming typed array for Object Animator's
434d430753cba09acb07af8b313286f247c78a41a32Chet Haase     *            attributes.
435d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * @param pixelSize The relative pixel size, used to calculate the
436d430753cba09acb07af8b313286f247c78a41a32Chet Haase     *                  maximum error for path animations.
437d430753cba09acb07af8b313286f247c78a41a32Chet Haase     */
438d430753cba09acb07af8b313286f247c78a41a32Chet Haase    private static void parseAnimatorFromTypeArray(ValueAnimator anim,
439d430753cba09acb07af8b313286f247c78a41a32Chet Haase            TypedArray arrayAnimator, TypedArray arrayObjectAnimator, float pixelSize) {
440d430753cba09acb07af8b313286f247c78a41a32Chet Haase        long duration = arrayAnimator.getInt(R.styleable.Animator_duration, 300);
441d430753cba09acb07af8b313286f247c78a41a32Chet Haase
442d430753cba09acb07af8b313286f247c78a41a32Chet Haase        long startDelay = arrayAnimator.getInt(R.styleable.Animator_startOffset, 0);
443d430753cba09acb07af8b313286f247c78a41a32Chet Haase
444d430753cba09acb07af8b313286f247c78a41a32Chet Haase        int valueType = arrayAnimator.getInt(R.styleable.Animator_valueType, VALUE_TYPE_FLOAT);
445d430753cba09acb07af8b313286f247c78a41a32Chet Haase
446d430753cba09acb07af8b313286f247c78a41a32Chet Haase        PropertyValuesHolder pvh = getPVH(arrayAnimator, valueType,
447d430753cba09acb07af8b313286f247c78a41a32Chet Haase                R.styleable.Animator_valueFrom, R.styleable.Animator_valueTo, "");
448d430753cba09acb07af8b313286f247c78a41a32Chet Haase        if (pvh != null) {
449d430753cba09acb07af8b313286f247c78a41a32Chet Haase            anim.setValues(pvh);
4505bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase        }
4515bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase
452eb034fbca40006c55db143047eb628c4b657730aztenghui        anim.setDuration(duration);
453eb034fbca40006c55db143047eb628c4b657730aztenghui        anim.setStartDelay(startDelay);
454eb034fbca40006c55db143047eb628c4b657730aztenghui
455eb034fbca40006c55db143047eb628c4b657730aztenghui        if (arrayAnimator.hasValue(R.styleable.Animator_repeatCount)) {
456eb034fbca40006c55db143047eb628c4b657730aztenghui            anim.setRepeatCount(
457eb034fbca40006c55db143047eb628c4b657730aztenghui                    arrayAnimator.getInt(R.styleable.Animator_repeatCount, 0));
458eb034fbca40006c55db143047eb628c4b657730aztenghui        }
459eb034fbca40006c55db143047eb628c4b657730aztenghui        if (arrayAnimator.hasValue(R.styleable.Animator_repeatMode)) {
460eb034fbca40006c55db143047eb628c4b657730aztenghui            anim.setRepeatMode(
461eb034fbca40006c55db143047eb628c4b657730aztenghui                    arrayAnimator.getInt(R.styleable.Animator_repeatMode,
462eb034fbca40006c55db143047eb628c4b657730aztenghui                            ValueAnimator.RESTART));
463eb034fbca40006c55db143047eb628c4b657730aztenghui        }
464eb034fbca40006c55db143047eb628c4b657730aztenghui
465eb034fbca40006c55db143047eb628c4b657730aztenghui        if (arrayObjectAnimator != null) {
466d430753cba09acb07af8b313286f247c78a41a32Chet Haase            setupObjectAnimator(anim, arrayObjectAnimator, valueType == VALUE_TYPE_FLOAT,
467d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    pixelSize);
468eb034fbca40006c55db143047eb628c4b657730aztenghui        }
469eb034fbca40006c55db143047eb628c4b657730aztenghui    }
470eb034fbca40006c55db143047eb628c4b657730aztenghui
471eb034fbca40006c55db143047eb628c4b657730aztenghui    /**
472eb034fbca40006c55db143047eb628c4b657730aztenghui     * Setup the Animator to achieve path morphing.
473eb034fbca40006c55db143047eb628c4b657730aztenghui     *
474eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param anim The target Animator which will be updated.
475eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param arrayAnimator TypedArray for the ValueAnimator.
476eb034fbca40006c55db143047eb628c4b657730aztenghui     * @return the PathDataEvaluator.
477eb034fbca40006c55db143047eb628c4b657730aztenghui     */
478eb034fbca40006c55db143047eb628c4b657730aztenghui    private static TypeEvaluator setupAnimatorForPath(ValueAnimator anim,
479eb034fbca40006c55db143047eb628c4b657730aztenghui             TypedArray arrayAnimator) {
480eb034fbca40006c55db143047eb628c4b657730aztenghui        TypeEvaluator evaluator = null;
481eb034fbca40006c55db143047eb628c4b657730aztenghui        String fromString = arrayAnimator.getString(R.styleable.Animator_valueFrom);
482eb034fbca40006c55db143047eb628c4b657730aztenghui        String toString = arrayAnimator.getString(R.styleable.Animator_valueTo);
483eb034fbca40006c55db143047eb628c4b657730aztenghui        PathParser.PathDataNode[] nodesFrom = PathParser.createNodesFromPathData(fromString);
484eb034fbca40006c55db143047eb628c4b657730aztenghui        PathParser.PathDataNode[] nodesTo = PathParser.createNodesFromPathData(toString);
485eb034fbca40006c55db143047eb628c4b657730aztenghui
486eb034fbca40006c55db143047eb628c4b657730aztenghui        if (nodesFrom != null) {
487eb034fbca40006c55db143047eb628c4b657730aztenghui            if (nodesTo != null) {
488eb034fbca40006c55db143047eb628c4b657730aztenghui                anim.setObjectValues(nodesFrom, nodesTo);
489eb034fbca40006c55db143047eb628c4b657730aztenghui                if (!PathParser.canMorph(nodesFrom, nodesTo)) {
490eb034fbca40006c55db143047eb628c4b657730aztenghui                    throw new InflateException(arrayAnimator.getPositionDescription()
491eb034fbca40006c55db143047eb628c4b657730aztenghui                            + " Can't morph from " + fromString + " to " + toString);
492eb034fbca40006c55db143047eb628c4b657730aztenghui                }
493eb034fbca40006c55db143047eb628c4b657730aztenghui            } else {
494eb034fbca40006c55db143047eb628c4b657730aztenghui                anim.setObjectValues((Object)nodesFrom);
495eb034fbca40006c55db143047eb628c4b657730aztenghui            }
496eb034fbca40006c55db143047eb628c4b657730aztenghui            evaluator = new PathDataEvaluator(PathParser.deepCopyNodes(nodesFrom));
497eb034fbca40006c55db143047eb628c4b657730aztenghui        } else if (nodesTo != null) {
498eb034fbca40006c55db143047eb628c4b657730aztenghui            anim.setObjectValues((Object)nodesTo);
499eb034fbca40006c55db143047eb628c4b657730aztenghui            evaluator = new PathDataEvaluator(PathParser.deepCopyNodes(nodesTo));
500eb034fbca40006c55db143047eb628c4b657730aztenghui        }
501eb034fbca40006c55db143047eb628c4b657730aztenghui
502eb034fbca40006c55db143047eb628c4b657730aztenghui        if (DBG_ANIMATOR_INFLATER && evaluator != null) {
503eb034fbca40006c55db143047eb628c4b657730aztenghui            Log.v(TAG, "create a new PathDataEvaluator here");
504eb034fbca40006c55db143047eb628c4b657730aztenghui        }
505eb034fbca40006c55db143047eb628c4b657730aztenghui
506eb034fbca40006c55db143047eb628c4b657730aztenghui        return evaluator;
507eb034fbca40006c55db143047eb628c4b657730aztenghui    }
508eb034fbca40006c55db143047eb628c4b657730aztenghui
509eb034fbca40006c55db143047eb628c4b657730aztenghui    /**
510eb034fbca40006c55db143047eb628c4b657730aztenghui     * Setup ObjectAnimator's property or values from pathData.
511eb034fbca40006c55db143047eb628c4b657730aztenghui     *
512eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param anim The target Animator which will be updated.
513eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param arrayObjectAnimator TypedArray for the ObjectAnimator.
514eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param getFloats True if the value type is float.
515fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount     * @param pixelSize The relative pixel size, used to calculate the
516fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount     *                  maximum error for path animations.
517eb034fbca40006c55db143047eb628c4b657730aztenghui     */
518eb034fbca40006c55db143047eb628c4b657730aztenghui    private static void setupObjectAnimator(ValueAnimator anim, TypedArray arrayObjectAnimator,
519fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount            boolean getFloats, float pixelSize) {
520eb034fbca40006c55db143047eb628c4b657730aztenghui        ObjectAnimator oa = (ObjectAnimator) anim;
521eb034fbca40006c55db143047eb628c4b657730aztenghui        String pathData = arrayObjectAnimator.getString(R.styleable.PropertyAnimator_pathData);
522eb034fbca40006c55db143047eb628c4b657730aztenghui
523eb034fbca40006c55db143047eb628c4b657730aztenghui        // Note that if there is a pathData defined in the Object Animator,
524eb034fbca40006c55db143047eb628c4b657730aztenghui        // valueFrom / valueTo will be ignored.
525eb034fbca40006c55db143047eb628c4b657730aztenghui        if (pathData != null) {
526eb034fbca40006c55db143047eb628c4b657730aztenghui            String propertyXName =
527eb034fbca40006c55db143047eb628c4b657730aztenghui                    arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyXName);
528eb034fbca40006c55db143047eb628c4b657730aztenghui            String propertyYName =
529eb034fbca40006c55db143047eb628c4b657730aztenghui                    arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyYName);
530eb034fbca40006c55db143047eb628c4b657730aztenghui
531eb034fbca40006c55db143047eb628c4b657730aztenghui            if (propertyXName == null && propertyYName == null) {
532eb034fbca40006c55db143047eb628c4b657730aztenghui                throw new InflateException(arrayObjectAnimator.getPositionDescription()
533eb034fbca40006c55db143047eb628c4b657730aztenghui                        + " propertyXName or propertyYName is needed for PathData");
534eb034fbca40006c55db143047eb628c4b657730aztenghui            } else {
535eb034fbca40006c55db143047eb628c4b657730aztenghui                Path path = PathParser.createPathFromPathData(pathData);
536fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount                float error = 0.5f * pixelSize; // max half a pixel error
537fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount                PathKeyframes keyframeSet = KeyframeSet.ofPath(path, error);
538984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                Keyframes xKeyframes;
539984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                Keyframes yKeyframes;
540984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                if (getFloats) {
541984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                    xKeyframes = keyframeSet.createXFloatKeyframes();
542984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                    yKeyframes = keyframeSet.createYFloatKeyframes();
543984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                } else {
544984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                    xKeyframes = keyframeSet.createXIntKeyframes();
545984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                    yKeyframes = keyframeSet.createYIntKeyframes();
546984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                }
547eb034fbca40006c55db143047eb628c4b657730aztenghui                PropertyValuesHolder x = null;
548eb034fbca40006c55db143047eb628c4b657730aztenghui                PropertyValuesHolder y = null;
549eb034fbca40006c55db143047eb628c4b657730aztenghui                if (propertyXName != null) {
550984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                    x = PropertyValuesHolder.ofKeyframes(propertyXName, xKeyframes);
551eb034fbca40006c55db143047eb628c4b657730aztenghui                }
552eb034fbca40006c55db143047eb628c4b657730aztenghui                if (propertyYName != null) {
553984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                    y = PropertyValuesHolder.ofKeyframes(propertyYName, yKeyframes);
554eb034fbca40006c55db143047eb628c4b657730aztenghui                }
555eb034fbca40006c55db143047eb628c4b657730aztenghui                if (x == null) {
556eb034fbca40006c55db143047eb628c4b657730aztenghui                    oa.setValues(y);
557eb034fbca40006c55db143047eb628c4b657730aztenghui                } else if (y == null) {
558eb034fbca40006c55db143047eb628c4b657730aztenghui                    oa.setValues(x);
559eb034fbca40006c55db143047eb628c4b657730aztenghui                } else {
560eb034fbca40006c55db143047eb628c4b657730aztenghui                    oa.setValues(x, y);
561eb034fbca40006c55db143047eb628c4b657730aztenghui                }
562eb034fbca40006c55db143047eb628c4b657730aztenghui            }
563eb034fbca40006c55db143047eb628c4b657730aztenghui        } else {
564eb034fbca40006c55db143047eb628c4b657730aztenghui            String propertyName =
565eb034fbca40006c55db143047eb628c4b657730aztenghui                    arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyName);
566eb034fbca40006c55db143047eb628c4b657730aztenghui            oa.setPropertyName(propertyName);
567eb034fbca40006c55db143047eb628c4b657730aztenghui        }
568eb034fbca40006c55db143047eb628c4b657730aztenghui    }
569eb034fbca40006c55db143047eb628c4b657730aztenghui
570eb034fbca40006c55db143047eb628c4b657730aztenghui    /**
571eb034fbca40006c55db143047eb628c4b657730aztenghui     * Setup ValueAnimator's values.
572eb034fbca40006c55db143047eb628c4b657730aztenghui     * This will handle all of the integer, float and color types.
573eb034fbca40006c55db143047eb628c4b657730aztenghui     *
574eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param anim The target Animator which will be updated.
575eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param arrayAnimator TypedArray for the ValueAnimator.
576eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param getFloats True if the value type is float.
577eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param hasFrom True if "valueFrom" exists.
578eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param fromType The type of "valueFrom".
579eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param hasTo True if "valueTo" exists.
580eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param toType The type of "valueTo".
581eb034fbca40006c55db143047eb628c4b657730aztenghui     */
582eb034fbca40006c55db143047eb628c4b657730aztenghui    private static void setupValues(ValueAnimator anim, TypedArray arrayAnimator,
583eb034fbca40006c55db143047eb628c4b657730aztenghui            boolean getFloats, boolean hasFrom, int fromType, boolean hasTo, int toType) {
584eb034fbca40006c55db143047eb628c4b657730aztenghui        int valueFromIndex = R.styleable.Animator_valueFrom;
585eb034fbca40006c55db143047eb628c4b657730aztenghui        int valueToIndex = R.styleable.Animator_valueTo;
5865bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase        if (getFloats) {
5875bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase            float valueFrom;
5885bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase            float valueTo;
5895bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase            if (hasFrom) {
5905bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                if (fromType == TypedValue.TYPE_DIMENSION) {
591cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                    valueFrom = arrayAnimator.getDimension(valueFromIndex, 0f);
5925bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                } else {
593cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                    valueFrom = arrayAnimator.getFloat(valueFromIndex, 0f);
5945bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                }
5955bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                if (hasTo) {
5965bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    if (toType == TypedValue.TYPE_DIMENSION) {
597cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                        valueTo = arrayAnimator.getDimension(valueToIndex, 0f);
5982794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase                    } else {
599cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                        valueTo = arrayAnimator.getFloat(valueToIndex, 0f);
6002794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase                    }
6015bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    anim.setFloatValues(valueFrom, valueTo);
6025bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                } else {
6035bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    anim.setFloatValues(valueFrom);
6045bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                }
6055bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase            } else {
6065bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                if (toType == TypedValue.TYPE_DIMENSION) {
607cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                    valueTo = arrayAnimator.getDimension(valueToIndex, 0f);
6082794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase                } else {
609cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                    valueTo = arrayAnimator.getFloat(valueToIndex, 0f);
610d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase                }
6115bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                anim.setFloatValues(valueTo);
6122794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase            }
6135bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase        } else {
6145bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase            int valueFrom;
6155bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase            int valueTo;
6165bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase            if (hasFrom) {
6175bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                if (fromType == TypedValue.TYPE_DIMENSION) {
618cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                    valueFrom = (int) arrayAnimator.getDimension(valueFromIndex, 0f);
6199032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu                } else if (isColorType(fromType)) {
620cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                    valueFrom = arrayAnimator.getColor(valueFromIndex, 0);
6215bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                } else {
622cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                    valueFrom = arrayAnimator.getInt(valueFromIndex, 0);
6235bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                }
6245bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                if (hasTo) {
6255bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    if (toType == TypedValue.TYPE_DIMENSION) {
626cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                        valueTo = (int) arrayAnimator.getDimension(valueToIndex, 0f);
6279032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu                    } else if (isColorType(toType)) {
628cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                        valueTo = arrayAnimator.getColor(valueToIndex, 0);
6292794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase                    } else {
630cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                        valueTo = arrayAnimator.getInt(valueToIndex, 0);
6312794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase                    }
6325bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    anim.setIntValues(valueFrom, valueTo);
6332794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase                } else {
6345bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    anim.setIntValues(valueFrom);
635d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase                }
6365bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase            } else {
6375bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                if (hasTo) {
6385bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    if (toType == TypedValue.TYPE_DIMENSION) {
639cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                        valueTo = (int) arrayAnimator.getDimension(valueToIndex, 0f);
6409032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu                    } else if (isColorType(toType)) {
641cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                        valueTo = arrayAnimator.getColor(valueToIndex, 0);
6422794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase                    } else {
643cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                        valueTo = arrayAnimator.getInt(valueToIndex, 0);
6442794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase                    }
6455bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    anim.setIntValues(valueTo);
646d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase                }
6472794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase            }
648d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        }
649e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    }
650e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
651fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount    private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser,
652fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount            float pixelSize)
653e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            throws XmlPullParserException, IOException {
654fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount        return createAnimatorFromXml(res, theme, parser, Xml.asAttributeSet(parser), null, 0,
655fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount                pixelSize);
656e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    }
657e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
658e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser,
659fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount            AttributeSet attrs, AnimatorSet parent, int sequenceOrdering, float pixelSize)
660e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            throws XmlPullParserException, IOException {
661e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        Animator anim = null;
662e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        ArrayList<Animator> childAnims = null;
663e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
664e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        // Make sure we are on a start tag.
665e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        int type;
666e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        int depth = parser.getDepth();
667e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
668e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
669e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                && type != XmlPullParser.END_DOCUMENT) {
670e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
671e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            if (type != XmlPullParser.START_TAG) {
672e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                continue;
673e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            }
674e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
675e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            String name = parser.getName();
676d430753cba09acb07af8b313286f247c78a41a32Chet Haase            boolean gotValues = false;
677e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
678e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            if (name.equals("objectAnimator")) {
679fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount                anim = loadObjectAnimator(res, theme, attrs, pixelSize);
680e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            } else if (name.equals("animator")) {
681fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount                anim = loadAnimator(res, theme, attrs, null, pixelSize);
682e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            } else if (name.equals("set")) {
683e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                anim = new AnimatorSet();
684e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                TypedArray a;
685e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                if (theme != null) {
686cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                    a = theme.obtainStyledAttributes(attrs, R.styleable.AnimatorSet, 0, 0);
687e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                } else {
688cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                    a = res.obtainAttributes(attrs, R.styleable.AnimatorSet);
689e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                }
690d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                anim.appendChangingConfigurations(a.getChangingConfigurations());
691d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                int ordering = a.getInt(R.styleable.AnimatorSet_ordering, TOGETHER);
692fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount                createAnimatorFromXml(res, theme, parser, attrs, (AnimatorSet) anim, ordering,
693fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount                        pixelSize);
694e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                a.recycle();
695d430753cba09acb07af8b313286f247c78a41a32Chet Haase            } else if (name.equals("propertyValuesHolder")) {
696d430753cba09acb07af8b313286f247c78a41a32Chet Haase                PropertyValuesHolder[] values = loadValues(res, theme, parser,
697d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        Xml.asAttributeSet(parser));
698d430753cba09acb07af8b313286f247c78a41a32Chet Haase                if (values != null && anim != null && (anim instanceof ValueAnimator)) {
699d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    ((ValueAnimator) anim).setValues(values);
700d430753cba09acb07af8b313286f247c78a41a32Chet Haase                }
701d430753cba09acb07af8b313286f247c78a41a32Chet Haase                gotValues = true;
702e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            } else {
703e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                throw new RuntimeException("Unknown animator name: " + parser.getName());
704e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            }
705e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
706d430753cba09acb07af8b313286f247c78a41a32Chet Haase            if (parent != null && !gotValues) {
707e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                if (childAnims == null) {
708e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                    childAnims = new ArrayList<Animator>();
709e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                }
710e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                childAnims.add(anim);
711e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            }
712e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
713e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        if (parent != null && childAnims != null) {
714e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            Animator[] animsArray = new Animator[childAnims.size()];
715e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            int index = 0;
716e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            for (Animator a : childAnims) {
717e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                animsArray[index++] = a;
718e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            }
719e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            if (sequenceOrdering == TOGETHER) {
720e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                parent.playTogether(animsArray);
721e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            } else {
722e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                parent.playSequentially(animsArray);
723e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            }
724e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
725e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        return anim;
726d430753cba09acb07af8b313286f247c78a41a32Chet Haase    }
727d430753cba09acb07af8b313286f247c78a41a32Chet Haase
728d430753cba09acb07af8b313286f247c78a41a32Chet Haase    private static PropertyValuesHolder[] loadValues(Resources res, Theme theme,
729d430753cba09acb07af8b313286f247c78a41a32Chet Haase            XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException, IOException {
730d430753cba09acb07af8b313286f247c78a41a32Chet Haase        ArrayList<PropertyValuesHolder> values = null;
731d430753cba09acb07af8b313286f247c78a41a32Chet Haase
732d430753cba09acb07af8b313286f247c78a41a32Chet Haase        int type;
733d430753cba09acb07af8b313286f247c78a41a32Chet Haase        while ((type = parser.getEventType()) != XmlPullParser.END_TAG &&
734d430753cba09acb07af8b313286f247c78a41a32Chet Haase                type != XmlPullParser.END_DOCUMENT) {
735d430753cba09acb07af8b313286f247c78a41a32Chet Haase
736d430753cba09acb07af8b313286f247c78a41a32Chet Haase            if (type != XmlPullParser.START_TAG) {
737d430753cba09acb07af8b313286f247c78a41a32Chet Haase                parser.next();
738d430753cba09acb07af8b313286f247c78a41a32Chet Haase                continue;
739d430753cba09acb07af8b313286f247c78a41a32Chet Haase            }
740d430753cba09acb07af8b313286f247c78a41a32Chet Haase
741d430753cba09acb07af8b313286f247c78a41a32Chet Haase            String name = parser.getName();
742d430753cba09acb07af8b313286f247c78a41a32Chet Haase
743d430753cba09acb07af8b313286f247c78a41a32Chet Haase            if (name.equals("propertyValuesHolder")) {
744d430753cba09acb07af8b313286f247c78a41a32Chet Haase                TypedArray a;
745d430753cba09acb07af8b313286f247c78a41a32Chet Haase                if (theme != null) {
746d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    a = theme.obtainStyledAttributes(attrs, R.styleable.PropertyValuesHolder, 0, 0);
747d430753cba09acb07af8b313286f247c78a41a32Chet Haase                } else {
748d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    a = res.obtainAttributes(attrs, R.styleable.PropertyValuesHolder);
749d430753cba09acb07af8b313286f247c78a41a32Chet Haase                }
750d430753cba09acb07af8b313286f247c78a41a32Chet Haase                String propertyName = a.getString(R.styleable.PropertyValuesHolder_propertyName);
751d430753cba09acb07af8b313286f247c78a41a32Chet Haase                int valueType = a.getInt(R.styleable.PropertyValuesHolder_valueType,
7529032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu                        VALUE_TYPE_UNDEFINED);
7539032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu
754d430753cba09acb07af8b313286f247c78a41a32Chet Haase                PropertyValuesHolder pvh = loadPvh(res, theme, parser, propertyName, valueType);
755d430753cba09acb07af8b313286f247c78a41a32Chet Haase                if (pvh == null) {
756d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    pvh = getPVH(a, valueType,
757d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            R.styleable.PropertyValuesHolder_valueFrom,
758d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            R.styleable.PropertyValuesHolder_valueTo, propertyName);
759d430753cba09acb07af8b313286f247c78a41a32Chet Haase                }
760d430753cba09acb07af8b313286f247c78a41a32Chet Haase                if (pvh != null) {
761d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    if (values == null) {
762d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        values = new ArrayList<PropertyValuesHolder>();
763d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    }
764d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    values.add(pvh);
765d430753cba09acb07af8b313286f247c78a41a32Chet Haase                }
766d430753cba09acb07af8b313286f247c78a41a32Chet Haase                a.recycle();
767d430753cba09acb07af8b313286f247c78a41a32Chet Haase            }
768d430753cba09acb07af8b313286f247c78a41a32Chet Haase
769d430753cba09acb07af8b313286f247c78a41a32Chet Haase            parser.next();
770d430753cba09acb07af8b313286f247c78a41a32Chet Haase        }
771d430753cba09acb07af8b313286f247c78a41a32Chet Haase
772d430753cba09acb07af8b313286f247c78a41a32Chet Haase        PropertyValuesHolder[] valuesArray = null;
773d430753cba09acb07af8b313286f247c78a41a32Chet Haase        if (values != null) {
774d430753cba09acb07af8b313286f247c78a41a32Chet Haase            int count = values.size();
775d430753cba09acb07af8b313286f247c78a41a32Chet Haase            valuesArray = new PropertyValuesHolder[count];
776d430753cba09acb07af8b313286f247c78a41a32Chet Haase            for (int i = 0; i < count; ++i) {
777d430753cba09acb07af8b313286f247c78a41a32Chet Haase                valuesArray[i] = values.get(i);
778d430753cba09acb07af8b313286f247c78a41a32Chet Haase            }
779d430753cba09acb07af8b313286f247c78a41a32Chet Haase        }
780d430753cba09acb07af8b313286f247c78a41a32Chet Haase        return valuesArray;
781d430753cba09acb07af8b313286f247c78a41a32Chet Haase    }
782d430753cba09acb07af8b313286f247c78a41a32Chet Haase
783d430753cba09acb07af8b313286f247c78a41a32Chet Haase    private static void dumpKeyframes(Object[] keyframes, String header) {
784d430753cba09acb07af8b313286f247c78a41a32Chet Haase        if (keyframes == null || keyframes.length == 0) {
785d430753cba09acb07af8b313286f247c78a41a32Chet Haase            return;
786d430753cba09acb07af8b313286f247c78a41a32Chet Haase        }
787d430753cba09acb07af8b313286f247c78a41a32Chet Haase        Log.d(TAG, header);
788d430753cba09acb07af8b313286f247c78a41a32Chet Haase        int count = keyframes.length;
789d430753cba09acb07af8b313286f247c78a41a32Chet Haase        for (int i = 0; i < count; ++i) {
790d430753cba09acb07af8b313286f247c78a41a32Chet Haase            Keyframe keyframe = (Keyframe) keyframes[i];
791d430753cba09acb07af8b313286f247c78a41a32Chet Haase            Log.d(TAG, "Keyframe " + i + ": fraction " +
792d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    (keyframe.getFraction() < 0 ? "null" : keyframe.getFraction()) + ", " +
793d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    ", value : " + ((keyframe.hasValue()) ? keyframe.getValue() : "null"));
794d430753cba09acb07af8b313286f247c78a41a32Chet Haase        }
795d430753cba09acb07af8b313286f247c78a41a32Chet Haase    }
796d430753cba09acb07af8b313286f247c78a41a32Chet Haase
7979032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu    // Load property values holder if there are keyframes defined in it. Otherwise return null.
798d430753cba09acb07af8b313286f247c78a41a32Chet Haase    private static PropertyValuesHolder loadPvh(Resources res, Theme theme, XmlPullParser parser,
799d430753cba09acb07af8b313286f247c78a41a32Chet Haase            String propertyName, int valueType)
800d430753cba09acb07af8b313286f247c78a41a32Chet Haase            throws XmlPullParserException, IOException {
801d430753cba09acb07af8b313286f247c78a41a32Chet Haase
802d430753cba09acb07af8b313286f247c78a41a32Chet Haase        PropertyValuesHolder value = null;
803d430753cba09acb07af8b313286f247c78a41a32Chet Haase        ArrayList<Keyframe> keyframes = null;
804d430753cba09acb07af8b313286f247c78a41a32Chet Haase
805d430753cba09acb07af8b313286f247c78a41a32Chet Haase        int type;
806d430753cba09acb07af8b313286f247c78a41a32Chet Haase        while ((type = parser.next()) != XmlPullParser.END_TAG &&
807d430753cba09acb07af8b313286f247c78a41a32Chet Haase                type != XmlPullParser.END_DOCUMENT) {
808d430753cba09acb07af8b313286f247c78a41a32Chet Haase            String name = parser.getName();
809d430753cba09acb07af8b313286f247c78a41a32Chet Haase            if (name.equals("keyframe")) {
810d430753cba09acb07af8b313286f247c78a41a32Chet Haase                Keyframe keyframe = loadKeyframe(res, theme, Xml.asAttributeSet(parser), valueType);
811d430753cba09acb07af8b313286f247c78a41a32Chet Haase                if (keyframe != null) {
812d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    if (keyframes == null) {
813d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        keyframes = new ArrayList<Keyframe>();
814d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    }
815d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    keyframes.add(keyframe);
816d430753cba09acb07af8b313286f247c78a41a32Chet Haase                }
817d430753cba09acb07af8b313286f247c78a41a32Chet Haase                parser.next();
818d430753cba09acb07af8b313286f247c78a41a32Chet Haase            }
819d430753cba09acb07af8b313286f247c78a41a32Chet Haase        }
820d430753cba09acb07af8b313286f247c78a41a32Chet Haase
821d430753cba09acb07af8b313286f247c78a41a32Chet Haase        int count;
822d430753cba09acb07af8b313286f247c78a41a32Chet Haase        if (keyframes != null && (count = keyframes.size()) > 0) {
823d430753cba09acb07af8b313286f247c78a41a32Chet Haase            // make sure we have keyframes at 0 and 1
824d430753cba09acb07af8b313286f247c78a41a32Chet Haase            // If we have keyframes with set fractions, add keyframes at start/end
825d430753cba09acb07af8b313286f247c78a41a32Chet Haase            // appropriately. If start/end have no set fractions:
826d430753cba09acb07af8b313286f247c78a41a32Chet Haase            // if there's only one keyframe, set its fraction to 1 and add one at 0
827d430753cba09acb07af8b313286f247c78a41a32Chet Haase            // if >1 keyframe, set the last fraction to 1, the first fraction to 0
828d430753cba09acb07af8b313286f247c78a41a32Chet Haase            Keyframe firstKeyframe = keyframes.get(0);
829d430753cba09acb07af8b313286f247c78a41a32Chet Haase            Keyframe lastKeyframe = keyframes.get(count - 1);
830d430753cba09acb07af8b313286f247c78a41a32Chet Haase            float endFraction = lastKeyframe.getFraction();
831d430753cba09acb07af8b313286f247c78a41a32Chet Haase            if (endFraction < 1) {
832d430753cba09acb07af8b313286f247c78a41a32Chet Haase                if (endFraction < 0) {
833d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    lastKeyframe.setFraction(1);
834d430753cba09acb07af8b313286f247c78a41a32Chet Haase                } else {
835d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    keyframes.add(keyframes.size(), createNewKeyframe(lastKeyframe, 1));
836d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    ++count;
837d430753cba09acb07af8b313286f247c78a41a32Chet Haase                }
838d430753cba09acb07af8b313286f247c78a41a32Chet Haase            }
839d430753cba09acb07af8b313286f247c78a41a32Chet Haase            float startFraction = firstKeyframe.getFraction();
840d430753cba09acb07af8b313286f247c78a41a32Chet Haase            if (startFraction != 0) {
841d430753cba09acb07af8b313286f247c78a41a32Chet Haase                if (startFraction < 0) {
842d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    firstKeyframe.setFraction(0);
843d430753cba09acb07af8b313286f247c78a41a32Chet Haase                } else {
844d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    keyframes.add(0, createNewKeyframe(firstKeyframe, 0));
845d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    ++count;
846d430753cba09acb07af8b313286f247c78a41a32Chet Haase                }
847d430753cba09acb07af8b313286f247c78a41a32Chet Haase            }
848d430753cba09acb07af8b313286f247c78a41a32Chet Haase            Keyframe[] keyframeArray = new Keyframe[count];
849d430753cba09acb07af8b313286f247c78a41a32Chet Haase            keyframes.toArray(keyframeArray);
850d430753cba09acb07af8b313286f247c78a41a32Chet Haase            for (int i = 0; i < count; ++i) {
851d430753cba09acb07af8b313286f247c78a41a32Chet Haase                Keyframe keyframe = keyframeArray[i];
852d430753cba09acb07af8b313286f247c78a41a32Chet Haase                if (keyframe.getFraction() < 0) {
853d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    if (i == 0) {
854d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        keyframe.setFraction(0);
855d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    } else if (i == count - 1) {
856d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        keyframe.setFraction(1);
857d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    } else {
858d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        // figure out the start/end parameters of the current gap
859d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        // in fractions and distribute the gap among those keyframes
860d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        int startIndex = i;
861d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        int endIndex = i;
862d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        for (int j = startIndex + 1; j < count - 1; ++j) {
863d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            if (keyframeArray[j].getFraction() >= 0) {
864d430753cba09acb07af8b313286f247c78a41a32Chet Haase                                break;
865d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            }
866d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            endIndex = j;
867d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        }
868d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        float gap = keyframeArray[endIndex + 1].getFraction() -
869d430753cba09acb07af8b313286f247c78a41a32Chet Haase                                keyframeArray[startIndex - 1].getFraction();
870d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        distributeKeyframes(keyframeArray, gap, startIndex, endIndex);
871d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    }
872d430753cba09acb07af8b313286f247c78a41a32Chet Haase                }
873d430753cba09acb07af8b313286f247c78a41a32Chet Haase            }
874d430753cba09acb07af8b313286f247c78a41a32Chet Haase            value = PropertyValuesHolder.ofKeyframe(propertyName, keyframeArray);
875d430753cba09acb07af8b313286f247c78a41a32Chet Haase            if (valueType == VALUE_TYPE_COLOR) {
876d430753cba09acb07af8b313286f247c78a41a32Chet Haase                value.setEvaluator(ArgbEvaluator.getInstance());
877d430753cba09acb07af8b313286f247c78a41a32Chet Haase            }
878d430753cba09acb07af8b313286f247c78a41a32Chet Haase        }
879d430753cba09acb07af8b313286f247c78a41a32Chet Haase
880d430753cba09acb07af8b313286f247c78a41a32Chet Haase        return value;
881d430753cba09acb07af8b313286f247c78a41a32Chet Haase    }
882d430753cba09acb07af8b313286f247c78a41a32Chet Haase
883d430753cba09acb07af8b313286f247c78a41a32Chet Haase    private static Keyframe createNewKeyframe(Keyframe sampleKeyframe, float fraction) {
884d430753cba09acb07af8b313286f247c78a41a32Chet Haase        return sampleKeyframe.getType() == float.class ?
885d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            Keyframe.ofFloat(fraction) :
886d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            (sampleKeyframe.getType() == int.class) ?
887d430753cba09acb07af8b313286f247c78a41a32Chet Haase                                    Keyframe.ofInt(fraction) :
888d430753cba09acb07af8b313286f247c78a41a32Chet Haase                                    Keyframe.ofObject(fraction);
889d430753cba09acb07af8b313286f247c78a41a32Chet Haase    }
890d430753cba09acb07af8b313286f247c78a41a32Chet Haase
891d430753cba09acb07af8b313286f247c78a41a32Chet Haase    /**
892d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * Utility function to set fractions on keyframes to cover a gap in which the
893d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * fractions are not currently set. Keyframe fractions will be distributed evenly
894d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * in this gap. For example, a gap of 1 keyframe in the range 0-1 will be at .5, a gap
895d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * of .6 spread between two keyframes will be at .2 and .4 beyond the fraction at the
896d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * keyframe before startIndex.
897d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * Assumptions:
898d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * - First and last keyframe fractions (bounding this spread) are already set. So,
899d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * for example, if no fractions are set, we will already set first and last keyframe
900d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * fraction values to 0 and 1.
901d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * - startIndex must be >0 (which follows from first assumption).
902d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * - endIndex must be >= startIndex.
903d430753cba09acb07af8b313286f247c78a41a32Chet Haase     *
904d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * @param keyframes the array of keyframes
905d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * @param gap The total gap we need to distribute
906d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * @param startIndex The index of the first keyframe whose fraction must be set
907d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * @param endIndex The index of the last keyframe whose fraction must be set
908d430753cba09acb07af8b313286f247c78a41a32Chet Haase     */
909d430753cba09acb07af8b313286f247c78a41a32Chet Haase    private static void distributeKeyframes(Keyframe[] keyframes, float gap,
910d430753cba09acb07af8b313286f247c78a41a32Chet Haase            int startIndex, int endIndex) {
911d430753cba09acb07af8b313286f247c78a41a32Chet Haase        int count = endIndex - startIndex + 2;
912d430753cba09acb07af8b313286f247c78a41a32Chet Haase        float increment = gap / count;
913d430753cba09acb07af8b313286f247c78a41a32Chet Haase        for (int i = startIndex; i <= endIndex; ++i) {
914d430753cba09acb07af8b313286f247c78a41a32Chet Haase            keyframes[i].setFraction(keyframes[i-1].getFraction() + increment);
915d430753cba09acb07af8b313286f247c78a41a32Chet Haase        }
916d430753cba09acb07af8b313286f247c78a41a32Chet Haase    }
917d430753cba09acb07af8b313286f247c78a41a32Chet Haase
918d430753cba09acb07af8b313286f247c78a41a32Chet Haase    private static Keyframe loadKeyframe(Resources res, Theme theme, AttributeSet attrs,
919d430753cba09acb07af8b313286f247c78a41a32Chet Haase            int valueType)
920d430753cba09acb07af8b313286f247c78a41a32Chet Haase            throws XmlPullParserException, IOException {
921d430753cba09acb07af8b313286f247c78a41a32Chet Haase
922d430753cba09acb07af8b313286f247c78a41a32Chet Haase        TypedArray a;
923d430753cba09acb07af8b313286f247c78a41a32Chet Haase        if (theme != null) {
924d430753cba09acb07af8b313286f247c78a41a32Chet Haase            a = theme.obtainStyledAttributes(attrs, R.styleable.Keyframe, 0, 0);
925d430753cba09acb07af8b313286f247c78a41a32Chet Haase        } else {
926d430753cba09acb07af8b313286f247c78a41a32Chet Haase            a = res.obtainAttributes(attrs, R.styleable.Keyframe);
927d430753cba09acb07af8b313286f247c78a41a32Chet Haase        }
928d430753cba09acb07af8b313286f247c78a41a32Chet Haase
929d430753cba09acb07af8b313286f247c78a41a32Chet Haase        Keyframe keyframe = null;
930d430753cba09acb07af8b313286f247c78a41a32Chet Haase
931d430753cba09acb07af8b313286f247c78a41a32Chet Haase        float fraction = a.getFloat(R.styleable.Keyframe_fraction, -1);
932d430753cba09acb07af8b313286f247c78a41a32Chet Haase
9339032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu        TypedValue keyframeValue = a.peekValue(R.styleable.Keyframe_value);
9349032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu        boolean hasValue = (keyframeValue != null);
9359032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu        if (valueType == VALUE_TYPE_UNDEFINED) {
9369032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu            // When no value type is provided, check whether it's a color type first.
9379032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu            // If not, fall back to default value type (i.e. float type).
9389032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu            if (hasValue && isColorType(keyframeValue.type)) {
9399032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu                valueType = VALUE_TYPE_COLOR;
9409032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu            } else {
9419032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu                valueType = VALUE_TYPE_FLOAT;
9429032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu            }
9439032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu        }
944d430753cba09acb07af8b313286f247c78a41a32Chet Haase
945d430753cba09acb07af8b313286f247c78a41a32Chet Haase        if (hasValue) {
946d430753cba09acb07af8b313286f247c78a41a32Chet Haase            switch (valueType) {
947d430753cba09acb07af8b313286f247c78a41a32Chet Haase                case VALUE_TYPE_FLOAT:
948d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    float value = a.getFloat(R.styleable.Keyframe_value, 0);
949d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    keyframe = Keyframe.ofFloat(fraction, value);
950d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    break;
951d430753cba09acb07af8b313286f247c78a41a32Chet Haase                case VALUE_TYPE_COLOR:
952d430753cba09acb07af8b313286f247c78a41a32Chet Haase                case VALUE_TYPE_INT:
953d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    int intValue = a.getInt(R.styleable.Keyframe_value, 0);
954d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    keyframe = Keyframe.ofInt(fraction, intValue);
955d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    break;
956d430753cba09acb07af8b313286f247c78a41a32Chet Haase            }
957d430753cba09acb07af8b313286f247c78a41a32Chet Haase        } else {
958d430753cba09acb07af8b313286f247c78a41a32Chet Haase            keyframe = (valueType == VALUE_TYPE_FLOAT) ? Keyframe.ofFloat(fraction) :
959d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    Keyframe.ofInt(fraction);
960d430753cba09acb07af8b313286f247c78a41a32Chet Haase        }
961d430753cba09acb07af8b313286f247c78a41a32Chet Haase
9626aac06ab940566020d050fdaa0d5e8d2e6c128aeDoris Liu        final int resID = a.getResourceId(R.styleable.Keyframe_interpolator, 0);
9636aac06ab940566020d050fdaa0d5e8d2e6c128aeDoris Liu        if (resID > 0) {
9646aac06ab940566020d050fdaa0d5e8d2e6c128aeDoris Liu            final Interpolator interpolator = AnimationUtils.loadInterpolator(res, theme, resID);
9656aac06ab940566020d050fdaa0d5e8d2e6c128aeDoris Liu            keyframe.setInterpolator(interpolator);
9666aac06ab940566020d050fdaa0d5e8d2e6c128aeDoris Liu        }
967d430753cba09acb07af8b313286f247c78a41a32Chet Haase        a.recycle();
968e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
969d430753cba09acb07af8b313286f247c78a41a32Chet Haase        return keyframe;
970e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    }
971e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
972fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount    private static ObjectAnimator loadObjectAnimator(Resources res, Theme theme, AttributeSet attrs,
973fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount            float pathErrorScale) throws NotFoundException {
974e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        ObjectAnimator anim = new ObjectAnimator();
975e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
976fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount        loadAnimator(res, theme, attrs, anim, pathErrorScale);
977e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
978e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        return anim;
979e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    }
980e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
981e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    /**
982e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * Creates a new animation whose parameters come from the specified context
983e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * and attributes set.
984e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     *
985e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * @param res The resources
986e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * @param attrs The set of attributes holding the animation parameters
987cf4832f69c8786b098ce18c24319021f8cd6733aztenghui     * @param anim Null if this is a ValueAnimator, otherwise this is an
988cf4832f69c8786b098ce18c24319021f8cd6733aztenghui     *            ObjectAnimator
989e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     */
990e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    private static ValueAnimator loadAnimator(Resources res, Theme theme,
991fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount            AttributeSet attrs, ValueAnimator anim, float pathErrorScale)
992e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            throws NotFoundException {
993cf4832f69c8786b098ce18c24319021f8cd6733aztenghui        TypedArray arrayAnimator = null;
994cf4832f69c8786b098ce18c24319021f8cd6733aztenghui        TypedArray arrayObjectAnimator = null;
995cf4832f69c8786b098ce18c24319021f8cd6733aztenghui
996e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        if (theme != null) {
997cf4832f69c8786b098ce18c24319021f8cd6733aztenghui            arrayAnimator = theme.obtainStyledAttributes(attrs, R.styleable.Animator, 0, 0);
998e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        } else {
999cf4832f69c8786b098ce18c24319021f8cd6733aztenghui            arrayAnimator = res.obtainAttributes(attrs, R.styleable.Animator);
1000e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1001e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1002cf4832f69c8786b098ce18c24319021f8cd6733aztenghui        // If anim is not null, then it is an object animator.
1003cf4832f69c8786b098ce18c24319021f8cd6733aztenghui        if (anim != null) {
1004cf4832f69c8786b098ce18c24319021f8cd6733aztenghui            if (theme != null) {
1005cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                arrayObjectAnimator = theme.obtainStyledAttributes(attrs,
1006cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                        R.styleable.PropertyAnimator, 0, 0);
1007cf4832f69c8786b098ce18c24319021f8cd6733aztenghui            } else {
1008cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                arrayObjectAnimator = res.obtainAttributes(attrs, R.styleable.PropertyAnimator);
1009cf4832f69c8786b098ce18c24319021f8cd6733aztenghui            }
1010d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            anim.appendChangingConfigurations(arrayObjectAnimator.getChangingConfigurations());
1011cf4832f69c8786b098ce18c24319021f8cd6733aztenghui        }
10127f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout
10137f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout        if (anim == null) {
10147f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout            anim = new ValueAnimator();
10157f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout        }
1016d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        anim.appendChangingConfigurations(arrayAnimator.getChangingConfigurations());
10177f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout
1018fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount        parseAnimatorFromTypeArray(anim, arrayAnimator, arrayObjectAnimator, pathErrorScale);
1019d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase
1020d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        final int resID = arrayAnimator.getResourceId(R.styleable.Animator_interpolator, 0);
1021d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        if (resID > 0) {
1022d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            final Interpolator interpolator = AnimationUtils.loadInterpolator(res, theme, resID);
1023d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            if (interpolator instanceof BaseInterpolator) {
1024d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                anim.appendChangingConfigurations(
1025d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                        ((BaseInterpolator) interpolator).getChangingConfiguration());
1026d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            }
1027d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            anim.setInterpolator(interpolator);
1028d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        }
1029cf4832f69c8786b098ce18c24319021f8cd6733aztenghui
1030cf4832f69c8786b098ce18c24319021f8cd6733aztenghui        arrayAnimator.recycle();
10317f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout        if (arrayObjectAnimator != null) {
10327f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout            arrayObjectAnimator.recycle();
10337f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout        }
1034d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        return anim;
1035d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase    }
1036d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar
1037d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar    private static int getChangingConfigs(Resources resources, int id) {
1038d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        synchronized (sTmpTypedValue) {
1039d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            resources.getValue(id, sTmpTypedValue, true);
1040d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            return sTmpTypedValue.changingConfigurations;
1041d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        }
1042d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar    }
10439032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu
10449032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu    private static boolean isColorType(int type) {
10459032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu       return (type >= TypedValue.TYPE_FIRST_COLOR_INT) && (type <= TypedValue.TYPE_LAST_COLOR_INT);
10469032fa5808d7808f54d31d646049d0b1f4a9491bDoris Liu    }
1047d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase}
1048