AnimatorInflater.java revision 6aac06ab940566020d050fdaa0d5e8d2e6c128ae
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;
71d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase
72eb034fbca40006c55db143047eb628c4b657730aztenghui    private static final boolean DBG_ANIMATOR_INFLATER = false;
73eb034fbca40006c55db143047eb628c4b657730aztenghui
74d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar    // used to calculate changing configs for resource references
75d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar    private static final TypedValue sTmpTypedValue = new TypedValue();
76d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar
77d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase    /**
78a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Loads an {@link Animator} object from a resource
79d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase     *
80d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase     * @param context Application context used to access resources
81d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase     * @param id The resource id of the animation to load
82a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * @return The animator object reference by the specified id
83d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase     * @throws android.content.res.Resources.NotFoundException when the animation cannot be loaded
84d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase     */
857b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbye    public static Animator loadAnimator(Context context, @AnimatorRes int id)
86d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase            throws NotFoundException {
87e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        return loadAnimator(context.getResources(), context.getTheme(), id);
88e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    }
89e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
90e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    /**
91e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * Loads an {@link Animator} object from a resource
92e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     *
93e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * @param resources The resources
94e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * @param theme The theme
95e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * @param id The resource id of the animation to load
96e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * @return The animator object reference by the specified id
97e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * @throws android.content.res.Resources.NotFoundException when the animation cannot be loaded
98e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * @hide
99e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     */
100e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    public static Animator loadAnimator(Resources resources, Theme theme, int id)
101e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            throws NotFoundException {
102fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount        return loadAnimator(resources, theme, id, 1);
103fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount    }
104fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount
105fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount    /** @hide */
106fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount    public static Animator loadAnimator(Resources resources, Theme theme, int id,
107fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount            float pathErrorScale) throws NotFoundException {
108d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        final ConfigurationBoundResourceCache<Animator> animatorCache = resources
109d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                .getAnimatorCache();
110d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        Animator animator = animatorCache.get(id, theme);
111d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        if (animator != null) {
112d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            if (DBG_ANIMATOR_INFLATER) {
113d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                Log.d(TAG, "loaded animator from cache, " + resources.getResourceName(id));
114d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            }
115d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            return animator;
116d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        } else if (DBG_ANIMATOR_INFLATER) {
117d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            Log.d(TAG, "cache miss for animator " + resources.getResourceName(id));
118d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        }
119d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        XmlResourceParser parser = null;
120d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        try {
121e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            parser = resources.getAnimation(id);
122d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            animator = createAnimatorFromXml(resources, theme, parser, pathErrorScale);
123d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            if (animator != null) {
124d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                animator.appendChangingConfigurations(getChangingConfigs(resources, id));
125d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                final ConstantState<Animator> constantState = animator.createConstantState();
126d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                if (constantState != null) {
127d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                    if (DBG_ANIMATOR_INFLATER) {
128d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                        Log.d(TAG, "caching animator for res " + resources.getResourceName(id));
129d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                    }
130d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                    animatorCache.put(id, theme, constantState);
131d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                    // create a new animator so that cached version is never used by the user
132d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                    animator = constantState.newInstance(resources, theme);
133d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                }
134d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            }
135d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            return animator;
136d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        } catch (XmlPullParserException ex) {
137d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase            Resources.NotFoundException rnf =
138d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase                    new Resources.NotFoundException("Can't load animation resource ID #0x" +
139fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount                            Integer.toHexString(id));
140d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase            rnf.initCause(ex);
141d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase            throw rnf;
142d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        } catch (IOException ex) {
143d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase            Resources.NotFoundException rnf =
144d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase                    new Resources.NotFoundException("Can't load animation resource ID #0x" +
145fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount                            Integer.toHexString(id));
146d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase            rnf.initCause(ex);
147d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase            throw rnf;
148d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        } finally {
149d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase            if (parser != null) parser.close();
150d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        }
151d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase    }
152d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase
153f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar    public static StateListAnimator loadStateListAnimator(Context context, int id)
154f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            throws NotFoundException {
155d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        final Resources resources = context.getResources();
156d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        final ConfigurationBoundResourceCache<StateListAnimator> cache = resources
157d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                .getStateListAnimatorCache();
158d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        final Theme theme = context.getTheme();
159d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        StateListAnimator animator = cache.get(id, theme);
160d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        if (animator != null) {
161d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            return animator;
162d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        }
163f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        XmlResourceParser parser = null;
164f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        try {
165d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            parser = resources.getAnimation(id);
166d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            animator = createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser));
167d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            if (animator != null) {
168d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                animator.appendChangingConfigurations(getChangingConfigs(resources, id));
169d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                final ConstantState<StateListAnimator> constantState = animator
170d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                        .createConstantState();
171d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                if (constantState != null) {
172d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                    cache.put(id, theme, constantState);
173d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                    // return a clone so that the animator in constant state is never used.
174d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                    animator = constantState.newInstance(resources, theme);
175d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                }
176d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            }
177d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            return animator;
178f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        } catch (XmlPullParserException ex) {
179f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            Resources.NotFoundException rnf =
180f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    new Resources.NotFoundException(
181f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                            "Can't load state list animator resource ID #0x" +
182f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                                    Integer.toHexString(id)
183f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    );
184f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            rnf.initCause(ex);
185f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            throw rnf;
186f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        } catch (IOException ex) {
187f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            Resources.NotFoundException rnf =
188f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    new Resources.NotFoundException(
189f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                            "Can't load state list animator resource ID #0x" +
190f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                                    Integer.toHexString(id)
191f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    );
192f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            rnf.initCause(ex);
193f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            throw rnf;
194f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        } finally {
195f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            if (parser != null) {
196f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                parser.close();
197f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            }
198f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        }
199f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar    }
200f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar
201f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar    private static StateListAnimator createStateListAnimatorFromXml(Context context,
202f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            XmlPullParser parser, AttributeSet attributeSet)
203f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            throws IOException, XmlPullParserException {
204f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        int type;
205f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        StateListAnimator stateListAnimator = new StateListAnimator();
206f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar
207f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        while (true) {
208f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            type = parser.next();
209f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            switch (type) {
210f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                case XmlPullParser.END_DOCUMENT:
211f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                case XmlPullParser.END_TAG:
212f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    return stateListAnimator;
213f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar
214f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                case XmlPullParser.START_TAG:
215f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    // parse item
216f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    Animator animator = null;
217f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    if ("item".equals(parser.getName())) {
218f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        int attributeCount = parser.getAttributeCount();
219f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        int[] states = new int[attributeCount];
220f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        int stateIndex = 0;
221f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        for (int i = 0; i < attributeCount; i++) {
222f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                            int attrName = attributeSet.getAttributeNameResource(i);
223cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                            if (attrName == R.attr.animation) {
224d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                                final int animId = attributeSet.getAttributeResourceValue(i, 0);
225d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                                animator = loadAnimator(context, animId);
226f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                            } else {
227f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                                states[stateIndex++] =
228f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                                        attributeSet.getAttributeBooleanValue(i, false) ?
229f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                                                attrName : -attrName;
230f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                            }
231f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        }
232f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        if (animator == null) {
233e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                            animator = createAnimatorFromXml(context.getResources(),
234fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount                                    context.getTheme(), parser, 1f);
235f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        }
236f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar
237f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        if (animator == null) {
238f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                            throw new Resources.NotFoundException(
239f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                                    "animation state item must have a valid animation");
240f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        }
241f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        stateListAnimator
242f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                                .addState(StateSet.trimStateSet(states, stateIndex), animator);
243f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    }
244f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    break;
245f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            }
246f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        }
247f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar    }
248f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar
249cf4832f69c8786b098ce18c24319021f8cd6733aztenghui    /**
250eb034fbca40006c55db143047eb628c4b657730aztenghui     * PathDataEvaluator is used to interpolate between two paths which are
251eb034fbca40006c55db143047eb628c4b657730aztenghui     * represented in the same format but different control points' values.
252eb034fbca40006c55db143047eb628c4b657730aztenghui     * The path is represented as an array of PathDataNode here, which is
253eb034fbca40006c55db143047eb628c4b657730aztenghui     * fundamentally an array of floating point numbers.
254eb034fbca40006c55db143047eb628c4b657730aztenghui     */
255eb034fbca40006c55db143047eb628c4b657730aztenghui    private static class PathDataEvaluator implements TypeEvaluator<PathParser.PathDataNode[]> {
256eb034fbca40006c55db143047eb628c4b657730aztenghui        private PathParser.PathDataNode[] mNodeArray;
257eb034fbca40006c55db143047eb628c4b657730aztenghui
258eb034fbca40006c55db143047eb628c4b657730aztenghui        /**
259eb034fbca40006c55db143047eb628c4b657730aztenghui         * Create a PathParser.PathDataNode[] that does not reuse the animated value.
260eb034fbca40006c55db143047eb628c4b657730aztenghui         * Care must be taken when using this option because on every evaluation
261eb034fbca40006c55db143047eb628c4b657730aztenghui         * a new <code>PathParser.PathDataNode[]</code> will be allocated.
262eb034fbca40006c55db143047eb628c4b657730aztenghui         */
263eb034fbca40006c55db143047eb628c4b657730aztenghui        private PathDataEvaluator() {}
264eb034fbca40006c55db143047eb628c4b657730aztenghui
265eb034fbca40006c55db143047eb628c4b657730aztenghui        /**
266eb034fbca40006c55db143047eb628c4b657730aztenghui         * Create a PathDataEvaluator that reuses <code>nodeArray</code> for every evaluate() call.
267eb034fbca40006c55db143047eb628c4b657730aztenghui         * Caution must be taken to ensure that the value returned from
268eb034fbca40006c55db143047eb628c4b657730aztenghui         * {@link android.animation.ValueAnimator#getAnimatedValue()} is not cached, modified, or
269eb034fbca40006c55db143047eb628c4b657730aztenghui         * used across threads. The value will be modified on each <code>evaluate()</code> call.
270eb034fbca40006c55db143047eb628c4b657730aztenghui         *
271eb034fbca40006c55db143047eb628c4b657730aztenghui         * @param nodeArray The array to modify and return from <code>evaluate</code>.
272eb034fbca40006c55db143047eb628c4b657730aztenghui         */
273eb034fbca40006c55db143047eb628c4b657730aztenghui        public PathDataEvaluator(PathParser.PathDataNode[] nodeArray) {
274eb034fbca40006c55db143047eb628c4b657730aztenghui            mNodeArray = nodeArray;
275eb034fbca40006c55db143047eb628c4b657730aztenghui        }
276eb034fbca40006c55db143047eb628c4b657730aztenghui
277eb034fbca40006c55db143047eb628c4b657730aztenghui        @Override
278eb034fbca40006c55db143047eb628c4b657730aztenghui        public PathParser.PathDataNode[] evaluate(float fraction,
279eb034fbca40006c55db143047eb628c4b657730aztenghui                PathParser.PathDataNode[] startPathData,
280eb034fbca40006c55db143047eb628c4b657730aztenghui                PathParser.PathDataNode[] endPathData) {
281eb034fbca40006c55db143047eb628c4b657730aztenghui            if (!PathParser.canMorph(startPathData, endPathData)) {
282eb034fbca40006c55db143047eb628c4b657730aztenghui                throw new IllegalArgumentException("Can't interpolate between"
283eb034fbca40006c55db143047eb628c4b657730aztenghui                        + " two incompatible pathData");
284eb034fbca40006c55db143047eb628c4b657730aztenghui            }
285eb034fbca40006c55db143047eb628c4b657730aztenghui
286eb034fbca40006c55db143047eb628c4b657730aztenghui            if (mNodeArray == null || !PathParser.canMorph(mNodeArray, startPathData)) {
287eb034fbca40006c55db143047eb628c4b657730aztenghui                mNodeArray = PathParser.deepCopyNodes(startPathData);
288eb034fbca40006c55db143047eb628c4b657730aztenghui            }
289eb034fbca40006c55db143047eb628c4b657730aztenghui
290eb034fbca40006c55db143047eb628c4b657730aztenghui            for (int i = 0; i < startPathData.length; i++) {
291eb034fbca40006c55db143047eb628c4b657730aztenghui                mNodeArray[i].interpolatePathDataNode(startPathData[i],
292eb034fbca40006c55db143047eb628c4b657730aztenghui                        endPathData[i], fraction);
293eb034fbca40006c55db143047eb628c4b657730aztenghui            }
294eb034fbca40006c55db143047eb628c4b657730aztenghui
295eb034fbca40006c55db143047eb628c4b657730aztenghui            return mNodeArray;
296eb034fbca40006c55db143047eb628c4b657730aztenghui        }
297eb034fbca40006c55db143047eb628c4b657730aztenghui    }
298eb034fbca40006c55db143047eb628c4b657730aztenghui
299d430753cba09acb07af8b313286f247c78a41a32Chet Haase    private static PropertyValuesHolder getPVH(TypedArray styledAttributes, int valueType,
300d430753cba09acb07af8b313286f247c78a41a32Chet Haase            int valueFromId, int valueToId, String propertyName) {
3015bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase
3025bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase        boolean getFloats = (valueType == VALUE_TYPE_FLOAT);
3035bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase
304d430753cba09acb07af8b313286f247c78a41a32Chet Haase        TypedValue tvFrom = styledAttributes.peekValue(valueFromId);
3055bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase        boolean hasFrom = (tvFrom != null);
3065bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase        int fromType = hasFrom ? tvFrom.type : 0;
307d430753cba09acb07af8b313286f247c78a41a32Chet Haase        TypedValue tvTo = styledAttributes.peekValue(valueToId);
3085bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase        boolean hasTo = (tvTo != null);
3095bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase        int toType = hasTo ? tvTo.type : 0;
3105bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase
311d430753cba09acb07af8b313286f247c78a41a32Chet Haase        PropertyValuesHolder returnValue = null;
312d430753cba09acb07af8b313286f247c78a41a32Chet Haase
313eb034fbca40006c55db143047eb628c4b657730aztenghui        if (valueType == VALUE_TYPE_PATH) {
314d430753cba09acb07af8b313286f247c78a41a32Chet Haase            String fromString = styledAttributes.getString(valueFromId);
315d430753cba09acb07af8b313286f247c78a41a32Chet Haase            String toString = styledAttributes.getString(valueToId);
316d430753cba09acb07af8b313286f247c78a41a32Chet Haase            PathParser.PathDataNode[] nodesFrom = PathParser.createNodesFromPathData(fromString);
317d430753cba09acb07af8b313286f247c78a41a32Chet Haase            PathParser.PathDataNode[] nodesTo = PathParser.createNodesFromPathData(toString);
318d430753cba09acb07af8b313286f247c78a41a32Chet Haase
319d430753cba09acb07af8b313286f247c78a41a32Chet Haase            if (nodesFrom != null || nodesTo != null) {
320d430753cba09acb07af8b313286f247c78a41a32Chet Haase                if (nodesFrom != null) {
321d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    TypeEvaluator evaluator =
322d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            new PathDataEvaluator(PathParser.deepCopyNodes(nodesFrom));
323d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    if (nodesTo != null) {
324d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        if (!PathParser.canMorph(nodesFrom, nodesTo)) {
325d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            throw new InflateException(" Can't morph from " + fromString + " to " +
326d430753cba09acb07af8b313286f247c78a41a32Chet Haase                                    toString);
327d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        }
328d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        returnValue = PropertyValuesHolder.ofObject(propertyName, evaluator,
329d430753cba09acb07af8b313286f247c78a41a32Chet Haase                                nodesFrom, nodesTo);
330d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    } else {
331d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        returnValue = PropertyValuesHolder.ofObject(propertyName, evaluator,
332d430753cba09acb07af8b313286f247c78a41a32Chet Haase                                (Object) nodesFrom);
333d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    }
334d430753cba09acb07af8b313286f247c78a41a32Chet Haase                } else if (nodesTo != null) {
335d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    TypeEvaluator evaluator =
336d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            new PathDataEvaluator(PathParser.deepCopyNodes(nodesTo));
337d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    returnValue = PropertyValuesHolder.ofObject(propertyName, evaluator,
338d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            (Object) nodesTo);
339d430753cba09acb07af8b313286f247c78a41a32Chet Haase                }
340d430753cba09acb07af8b313286f247c78a41a32Chet Haase            }
341eb034fbca40006c55db143047eb628c4b657730aztenghui        } else {
342d430753cba09acb07af8b313286f247c78a41a32Chet Haase            TypeEvaluator evaluator = null;
343eb034fbca40006c55db143047eb628c4b657730aztenghui            // Integer and float value types are handled here.
344eb034fbca40006c55db143047eb628c4b657730aztenghui            if ((hasFrom && (fromType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
345eb034fbca40006c55db143047eb628c4b657730aztenghui                    (fromType <= TypedValue.TYPE_LAST_COLOR_INT)) ||
346eb034fbca40006c55db143047eb628c4b657730aztenghui                    (hasTo && (toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
347eb034fbca40006c55db143047eb628c4b657730aztenghui                            (toType <= TypedValue.TYPE_LAST_COLOR_INT))) {
348eb034fbca40006c55db143047eb628c4b657730aztenghui                // special case for colors: ignore valueType and get ints
349eb034fbca40006c55db143047eb628c4b657730aztenghui                getFloats = false;
350eb034fbca40006c55db143047eb628c4b657730aztenghui                evaluator = ArgbEvaluator.getInstance();
351eb034fbca40006c55db143047eb628c4b657730aztenghui            }
352d430753cba09acb07af8b313286f247c78a41a32Chet Haase            if (getFloats) {
353d430753cba09acb07af8b313286f247c78a41a32Chet Haase                float valueFrom;
354d430753cba09acb07af8b313286f247c78a41a32Chet Haase                float valueTo;
355d430753cba09acb07af8b313286f247c78a41a32Chet Haase                if (hasFrom) {
356d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    if (fromType == TypedValue.TYPE_DIMENSION) {
357d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        valueFrom = styledAttributes.getDimension(valueFromId, 0f);
358d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    } else {
359d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        valueFrom = styledAttributes.getFloat(valueFromId, 0f);
360d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    }
361d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    if (hasTo) {
362d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        if (toType == TypedValue.TYPE_DIMENSION) {
363d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            valueTo = styledAttributes.getDimension(valueToId, 0f);
364d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        } else {
365d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            valueTo = styledAttributes.getFloat(valueToId, 0f);
366d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        }
367d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        returnValue = PropertyValuesHolder.ofFloat(propertyName,
368d430753cba09acb07af8b313286f247c78a41a32Chet Haase                                valueFrom, valueTo);
369d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    } else {
370d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        returnValue = PropertyValuesHolder.ofFloat(propertyName, valueFrom);
371d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    }
372d430753cba09acb07af8b313286f247c78a41a32Chet Haase                } else {
373d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    if (toType == TypedValue.TYPE_DIMENSION) {
374d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        valueTo = styledAttributes.getDimension(valueToId, 0f);
375d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    } else {
376d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        valueTo = styledAttributes.getFloat(valueToId, 0f);
377d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    }
378d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    returnValue = PropertyValuesHolder.ofFloat(propertyName, valueTo);
379d430753cba09acb07af8b313286f247c78a41a32Chet Haase                }
380d430753cba09acb07af8b313286f247c78a41a32Chet Haase            } else {
381d430753cba09acb07af8b313286f247c78a41a32Chet Haase                int valueFrom;
382d430753cba09acb07af8b313286f247c78a41a32Chet Haase                int valueTo;
383d430753cba09acb07af8b313286f247c78a41a32Chet Haase                if (hasFrom) {
384d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    if (fromType == TypedValue.TYPE_DIMENSION) {
385d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        valueFrom = (int) styledAttributes.getDimension(valueFromId, 0f);
386d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    } else if ((fromType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
387d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            (fromType <= TypedValue.TYPE_LAST_COLOR_INT)) {
388d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        valueFrom = styledAttributes.getColor(valueFromId, 0);
389d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    } else {
390d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        valueFrom = styledAttributes.getInt(valueFromId, 0);
391d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    }
392d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    if (hasTo) {
393d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        if (toType == TypedValue.TYPE_DIMENSION) {
394d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            valueTo = (int) styledAttributes.getDimension(valueToId, 0f);
395d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        } else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
396d430753cba09acb07af8b313286f247c78a41a32Chet Haase                                (toType <= TypedValue.TYPE_LAST_COLOR_INT)) {
397d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            valueTo = styledAttributes.getColor(valueToId, 0);
398d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        } else {
399d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            valueTo = styledAttributes.getInt(valueToId, 0);
400d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        }
401d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        returnValue = PropertyValuesHolder.ofInt(propertyName, valueFrom, valueTo);
402d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    } else {
403d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        returnValue = PropertyValuesHolder.ofInt(propertyName, valueFrom);
404d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    }
405d430753cba09acb07af8b313286f247c78a41a32Chet Haase                } else {
406d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    if (hasTo) {
407d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        if (toType == TypedValue.TYPE_DIMENSION) {
408d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            valueTo = (int) styledAttributes.getDimension(valueToId, 0f);
409d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        } else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
410d430753cba09acb07af8b313286f247c78a41a32Chet Haase                                (toType <= TypedValue.TYPE_LAST_COLOR_INT)) {
411d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            valueTo = styledAttributes.getColor(valueToId, 0);
412d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        } else {
413d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            valueTo = styledAttributes.getInt(valueToId, 0);
414d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        }
415d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        returnValue = PropertyValuesHolder.ofInt(propertyName, valueTo);
416d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    }
417d430753cba09acb07af8b313286f247c78a41a32Chet Haase                }
418d430753cba09acb07af8b313286f247c78a41a32Chet Haase            }
419d430753cba09acb07af8b313286f247c78a41a32Chet Haase            if (returnValue != null && evaluator != null) {
420d430753cba09acb07af8b313286f247c78a41a32Chet Haase                returnValue.setEvaluator(evaluator);
421d430753cba09acb07af8b313286f247c78a41a32Chet Haase            }
422d430753cba09acb07af8b313286f247c78a41a32Chet Haase        }
423d430753cba09acb07af8b313286f247c78a41a32Chet Haase
424d430753cba09acb07af8b313286f247c78a41a32Chet Haase        return returnValue;
425d430753cba09acb07af8b313286f247c78a41a32Chet Haase    }
426d430753cba09acb07af8b313286f247c78a41a32Chet Haase
427d430753cba09acb07af8b313286f247c78a41a32Chet Haase    /**
428d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * @param anim The animator, must not be null
429d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * @param arrayAnimator Incoming typed array for Animator's attributes.
430d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * @param arrayObjectAnimator Incoming typed array for Object Animator's
431d430753cba09acb07af8b313286f247c78a41a32Chet Haase     *            attributes.
432d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * @param pixelSize The relative pixel size, used to calculate the
433d430753cba09acb07af8b313286f247c78a41a32Chet Haase     *                  maximum error for path animations.
434d430753cba09acb07af8b313286f247c78a41a32Chet Haase     */
435d430753cba09acb07af8b313286f247c78a41a32Chet Haase    private static void parseAnimatorFromTypeArray(ValueAnimator anim,
436d430753cba09acb07af8b313286f247c78a41a32Chet Haase            TypedArray arrayAnimator, TypedArray arrayObjectAnimator, float pixelSize) {
437d430753cba09acb07af8b313286f247c78a41a32Chet Haase        long duration = arrayAnimator.getInt(R.styleable.Animator_duration, 300);
438d430753cba09acb07af8b313286f247c78a41a32Chet Haase
439d430753cba09acb07af8b313286f247c78a41a32Chet Haase        long startDelay = arrayAnimator.getInt(R.styleable.Animator_startOffset, 0);
440d430753cba09acb07af8b313286f247c78a41a32Chet Haase
441d430753cba09acb07af8b313286f247c78a41a32Chet Haase        int valueType = arrayAnimator.getInt(R.styleable.Animator_valueType, VALUE_TYPE_FLOAT);
442d430753cba09acb07af8b313286f247c78a41a32Chet Haase
443d430753cba09acb07af8b313286f247c78a41a32Chet Haase        PropertyValuesHolder pvh = getPVH(arrayAnimator, valueType,
444d430753cba09acb07af8b313286f247c78a41a32Chet Haase                R.styleable.Animator_valueFrom, R.styleable.Animator_valueTo, "");
445d430753cba09acb07af8b313286f247c78a41a32Chet Haase        if (pvh != null) {
446d430753cba09acb07af8b313286f247c78a41a32Chet Haase            anim.setValues(pvh);
4475bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase        }
4485bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase
449eb034fbca40006c55db143047eb628c4b657730aztenghui        anim.setDuration(duration);
450eb034fbca40006c55db143047eb628c4b657730aztenghui        anim.setStartDelay(startDelay);
451eb034fbca40006c55db143047eb628c4b657730aztenghui
452eb034fbca40006c55db143047eb628c4b657730aztenghui        if (arrayAnimator.hasValue(R.styleable.Animator_repeatCount)) {
453eb034fbca40006c55db143047eb628c4b657730aztenghui            anim.setRepeatCount(
454eb034fbca40006c55db143047eb628c4b657730aztenghui                    arrayAnimator.getInt(R.styleable.Animator_repeatCount, 0));
455eb034fbca40006c55db143047eb628c4b657730aztenghui        }
456eb034fbca40006c55db143047eb628c4b657730aztenghui        if (arrayAnimator.hasValue(R.styleable.Animator_repeatMode)) {
457eb034fbca40006c55db143047eb628c4b657730aztenghui            anim.setRepeatMode(
458eb034fbca40006c55db143047eb628c4b657730aztenghui                    arrayAnimator.getInt(R.styleable.Animator_repeatMode,
459eb034fbca40006c55db143047eb628c4b657730aztenghui                            ValueAnimator.RESTART));
460eb034fbca40006c55db143047eb628c4b657730aztenghui        }
461eb034fbca40006c55db143047eb628c4b657730aztenghui
462eb034fbca40006c55db143047eb628c4b657730aztenghui        if (arrayObjectAnimator != null) {
463d430753cba09acb07af8b313286f247c78a41a32Chet Haase            setupObjectAnimator(anim, arrayObjectAnimator, valueType == VALUE_TYPE_FLOAT,
464d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    pixelSize);
465eb034fbca40006c55db143047eb628c4b657730aztenghui        }
466eb034fbca40006c55db143047eb628c4b657730aztenghui    }
467eb034fbca40006c55db143047eb628c4b657730aztenghui
468eb034fbca40006c55db143047eb628c4b657730aztenghui    /**
469eb034fbca40006c55db143047eb628c4b657730aztenghui     * Setup the Animator to achieve path morphing.
470eb034fbca40006c55db143047eb628c4b657730aztenghui     *
471eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param anim The target Animator which will be updated.
472eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param arrayAnimator TypedArray for the ValueAnimator.
473eb034fbca40006c55db143047eb628c4b657730aztenghui     * @return the PathDataEvaluator.
474eb034fbca40006c55db143047eb628c4b657730aztenghui     */
475eb034fbca40006c55db143047eb628c4b657730aztenghui    private static TypeEvaluator setupAnimatorForPath(ValueAnimator anim,
476eb034fbca40006c55db143047eb628c4b657730aztenghui             TypedArray arrayAnimator) {
477eb034fbca40006c55db143047eb628c4b657730aztenghui        TypeEvaluator evaluator = null;
478eb034fbca40006c55db143047eb628c4b657730aztenghui        String fromString = arrayAnimator.getString(R.styleable.Animator_valueFrom);
479eb034fbca40006c55db143047eb628c4b657730aztenghui        String toString = arrayAnimator.getString(R.styleable.Animator_valueTo);
480eb034fbca40006c55db143047eb628c4b657730aztenghui        PathParser.PathDataNode[] nodesFrom = PathParser.createNodesFromPathData(fromString);
481eb034fbca40006c55db143047eb628c4b657730aztenghui        PathParser.PathDataNode[] nodesTo = PathParser.createNodesFromPathData(toString);
482eb034fbca40006c55db143047eb628c4b657730aztenghui
483eb034fbca40006c55db143047eb628c4b657730aztenghui        if (nodesFrom != null) {
484eb034fbca40006c55db143047eb628c4b657730aztenghui            if (nodesTo != null) {
485eb034fbca40006c55db143047eb628c4b657730aztenghui                anim.setObjectValues(nodesFrom, nodesTo);
486eb034fbca40006c55db143047eb628c4b657730aztenghui                if (!PathParser.canMorph(nodesFrom, nodesTo)) {
487eb034fbca40006c55db143047eb628c4b657730aztenghui                    throw new InflateException(arrayAnimator.getPositionDescription()
488eb034fbca40006c55db143047eb628c4b657730aztenghui                            + " Can't morph from " + fromString + " to " + toString);
489eb034fbca40006c55db143047eb628c4b657730aztenghui                }
490eb034fbca40006c55db143047eb628c4b657730aztenghui            } else {
491eb034fbca40006c55db143047eb628c4b657730aztenghui                anim.setObjectValues((Object)nodesFrom);
492eb034fbca40006c55db143047eb628c4b657730aztenghui            }
493eb034fbca40006c55db143047eb628c4b657730aztenghui            evaluator = new PathDataEvaluator(PathParser.deepCopyNodes(nodesFrom));
494eb034fbca40006c55db143047eb628c4b657730aztenghui        } else if (nodesTo != null) {
495eb034fbca40006c55db143047eb628c4b657730aztenghui            anim.setObjectValues((Object)nodesTo);
496eb034fbca40006c55db143047eb628c4b657730aztenghui            evaluator = new PathDataEvaluator(PathParser.deepCopyNodes(nodesTo));
497eb034fbca40006c55db143047eb628c4b657730aztenghui        }
498eb034fbca40006c55db143047eb628c4b657730aztenghui
499eb034fbca40006c55db143047eb628c4b657730aztenghui        if (DBG_ANIMATOR_INFLATER && evaluator != null) {
500eb034fbca40006c55db143047eb628c4b657730aztenghui            Log.v(TAG, "create a new PathDataEvaluator here");
501eb034fbca40006c55db143047eb628c4b657730aztenghui        }
502eb034fbca40006c55db143047eb628c4b657730aztenghui
503eb034fbca40006c55db143047eb628c4b657730aztenghui        return evaluator;
504eb034fbca40006c55db143047eb628c4b657730aztenghui    }
505eb034fbca40006c55db143047eb628c4b657730aztenghui
506eb034fbca40006c55db143047eb628c4b657730aztenghui    /**
507eb034fbca40006c55db143047eb628c4b657730aztenghui     * Setup ObjectAnimator's property or values from pathData.
508eb034fbca40006c55db143047eb628c4b657730aztenghui     *
509eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param anim The target Animator which will be updated.
510eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param arrayObjectAnimator TypedArray for the ObjectAnimator.
511eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param getFloats True if the value type is float.
512fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount     * @param pixelSize The relative pixel size, used to calculate the
513fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount     *                  maximum error for path animations.
514eb034fbca40006c55db143047eb628c4b657730aztenghui     */
515eb034fbca40006c55db143047eb628c4b657730aztenghui    private static void setupObjectAnimator(ValueAnimator anim, TypedArray arrayObjectAnimator,
516fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount            boolean getFloats, float pixelSize) {
517eb034fbca40006c55db143047eb628c4b657730aztenghui        ObjectAnimator oa = (ObjectAnimator) anim;
518eb034fbca40006c55db143047eb628c4b657730aztenghui        String pathData = arrayObjectAnimator.getString(R.styleable.PropertyAnimator_pathData);
519eb034fbca40006c55db143047eb628c4b657730aztenghui
520eb034fbca40006c55db143047eb628c4b657730aztenghui        // Note that if there is a pathData defined in the Object Animator,
521eb034fbca40006c55db143047eb628c4b657730aztenghui        // valueFrom / valueTo will be ignored.
522eb034fbca40006c55db143047eb628c4b657730aztenghui        if (pathData != null) {
523eb034fbca40006c55db143047eb628c4b657730aztenghui            String propertyXName =
524eb034fbca40006c55db143047eb628c4b657730aztenghui                    arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyXName);
525eb034fbca40006c55db143047eb628c4b657730aztenghui            String propertyYName =
526eb034fbca40006c55db143047eb628c4b657730aztenghui                    arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyYName);
527eb034fbca40006c55db143047eb628c4b657730aztenghui
528eb034fbca40006c55db143047eb628c4b657730aztenghui            if (propertyXName == null && propertyYName == null) {
529eb034fbca40006c55db143047eb628c4b657730aztenghui                throw new InflateException(arrayObjectAnimator.getPositionDescription()
530eb034fbca40006c55db143047eb628c4b657730aztenghui                        + " propertyXName or propertyYName is needed for PathData");
531eb034fbca40006c55db143047eb628c4b657730aztenghui            } else {
532eb034fbca40006c55db143047eb628c4b657730aztenghui                Path path = PathParser.createPathFromPathData(pathData);
533fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount                float error = 0.5f * pixelSize; // max half a pixel error
534fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount                PathKeyframes keyframeSet = KeyframeSet.ofPath(path, error);
535984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                Keyframes xKeyframes;
536984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                Keyframes yKeyframes;
537984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                if (getFloats) {
538984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                    xKeyframes = keyframeSet.createXFloatKeyframes();
539984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                    yKeyframes = keyframeSet.createYFloatKeyframes();
540984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                } else {
541984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                    xKeyframes = keyframeSet.createXIntKeyframes();
542984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                    yKeyframes = keyframeSet.createYIntKeyframes();
543984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                }
544eb034fbca40006c55db143047eb628c4b657730aztenghui                PropertyValuesHolder x = null;
545eb034fbca40006c55db143047eb628c4b657730aztenghui                PropertyValuesHolder y = null;
546eb034fbca40006c55db143047eb628c4b657730aztenghui                if (propertyXName != null) {
547984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                    x = PropertyValuesHolder.ofKeyframes(propertyXName, xKeyframes);
548eb034fbca40006c55db143047eb628c4b657730aztenghui                }
549eb034fbca40006c55db143047eb628c4b657730aztenghui                if (propertyYName != null) {
550984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                    y = PropertyValuesHolder.ofKeyframes(propertyYName, yKeyframes);
551eb034fbca40006c55db143047eb628c4b657730aztenghui                }
552eb034fbca40006c55db143047eb628c4b657730aztenghui                if (x == null) {
553eb034fbca40006c55db143047eb628c4b657730aztenghui                    oa.setValues(y);
554eb034fbca40006c55db143047eb628c4b657730aztenghui                } else if (y == null) {
555eb034fbca40006c55db143047eb628c4b657730aztenghui                    oa.setValues(x);
556eb034fbca40006c55db143047eb628c4b657730aztenghui                } else {
557eb034fbca40006c55db143047eb628c4b657730aztenghui                    oa.setValues(x, y);
558eb034fbca40006c55db143047eb628c4b657730aztenghui                }
559eb034fbca40006c55db143047eb628c4b657730aztenghui            }
560eb034fbca40006c55db143047eb628c4b657730aztenghui        } else {
561eb034fbca40006c55db143047eb628c4b657730aztenghui            String propertyName =
562eb034fbca40006c55db143047eb628c4b657730aztenghui                    arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyName);
563eb034fbca40006c55db143047eb628c4b657730aztenghui            oa.setPropertyName(propertyName);
564eb034fbca40006c55db143047eb628c4b657730aztenghui        }
565eb034fbca40006c55db143047eb628c4b657730aztenghui    }
566eb034fbca40006c55db143047eb628c4b657730aztenghui
567eb034fbca40006c55db143047eb628c4b657730aztenghui    /**
568eb034fbca40006c55db143047eb628c4b657730aztenghui     * Setup ValueAnimator's values.
569eb034fbca40006c55db143047eb628c4b657730aztenghui     * This will handle all of the integer, float and color types.
570eb034fbca40006c55db143047eb628c4b657730aztenghui     *
571eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param anim The target Animator which will be updated.
572eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param arrayAnimator TypedArray for the ValueAnimator.
573eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param getFloats True if the value type is float.
574eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param hasFrom True if "valueFrom" exists.
575eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param fromType The type of "valueFrom".
576eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param hasTo True if "valueTo" exists.
577eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param toType The type of "valueTo".
578eb034fbca40006c55db143047eb628c4b657730aztenghui     */
579eb034fbca40006c55db143047eb628c4b657730aztenghui    private static void setupValues(ValueAnimator anim, TypedArray arrayAnimator,
580eb034fbca40006c55db143047eb628c4b657730aztenghui            boolean getFloats, boolean hasFrom, int fromType, boolean hasTo, int toType) {
581eb034fbca40006c55db143047eb628c4b657730aztenghui        int valueFromIndex = R.styleable.Animator_valueFrom;
582eb034fbca40006c55db143047eb628c4b657730aztenghui        int valueToIndex = R.styleable.Animator_valueTo;
5835bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase        if (getFloats) {
5845bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase            float valueFrom;
5855bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase            float valueTo;
5865bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase            if (hasFrom) {
5875bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                if (fromType == TypedValue.TYPE_DIMENSION) {
588cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                    valueFrom = arrayAnimator.getDimension(valueFromIndex, 0f);
5895bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                } else {
590cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                    valueFrom = arrayAnimator.getFloat(valueFromIndex, 0f);
5915bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                }
5925bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                if (hasTo) {
5935bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    if (toType == TypedValue.TYPE_DIMENSION) {
594cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                        valueTo = arrayAnimator.getDimension(valueToIndex, 0f);
5952794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase                    } else {
596cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                        valueTo = arrayAnimator.getFloat(valueToIndex, 0f);
5972794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase                    }
5985bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    anim.setFloatValues(valueFrom, valueTo);
5995bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                } else {
6005bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    anim.setFloatValues(valueFrom);
6015bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                }
6025bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase            } else {
6035bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                if (toType == TypedValue.TYPE_DIMENSION) {
604cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                    valueTo = arrayAnimator.getDimension(valueToIndex, 0f);
6052794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase                } else {
606cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                    valueTo = arrayAnimator.getFloat(valueToIndex, 0f);
607d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase                }
6085bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                anim.setFloatValues(valueTo);
6092794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase            }
6105bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase        } else {
6115bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase            int valueFrom;
6125bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase            int valueTo;
6135bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase            if (hasFrom) {
6145bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                if (fromType == TypedValue.TYPE_DIMENSION) {
615cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                    valueFrom = (int) arrayAnimator.getDimension(valueFromIndex, 0f);
6165bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                } else if ((fromType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
6175bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                        (fromType <= TypedValue.TYPE_LAST_COLOR_INT)) {
618cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                    valueFrom = arrayAnimator.getColor(valueFromIndex, 0);
6195bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                } else {
620cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                    valueFrom = arrayAnimator.getInt(valueFromIndex, 0);
6215bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                }
6225bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                if (hasTo) {
6235bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    if (toType == TypedValue.TYPE_DIMENSION) {
624cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                        valueTo = (int) arrayAnimator.getDimension(valueToIndex, 0f);
6255bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    } else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
6265bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                            (toType <= TypedValue.TYPE_LAST_COLOR_INT)) {
627cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                        valueTo = arrayAnimator.getColor(valueToIndex, 0);
6282794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase                    } else {
629cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                        valueTo = arrayAnimator.getInt(valueToIndex, 0);
6302794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase                    }
6315bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    anim.setIntValues(valueFrom, valueTo);
6322794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase                } else {
6335bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    anim.setIntValues(valueFrom);
634d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase                }
6355bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase            } else {
6365bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                if (hasTo) {
6375bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    if (toType == TypedValue.TYPE_DIMENSION) {
638cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                        valueTo = (int) arrayAnimator.getDimension(valueToIndex, 0f);
6395bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    } else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
640cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                            (toType <= TypedValue.TYPE_LAST_COLOR_INT)) {
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,
752d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        VALUE_TYPE_FLOAT);
753d430753cba09acb07af8b313286f247c78a41a32Chet Haase                PropertyValuesHolder pvh = loadPvh(res, theme, parser, propertyName, valueType);
754d430753cba09acb07af8b313286f247c78a41a32Chet Haase                if (pvh == null) {
755d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    pvh = getPVH(a, valueType,
756d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            R.styleable.PropertyValuesHolder_valueFrom,
757d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            R.styleable.PropertyValuesHolder_valueTo, propertyName);
758d430753cba09acb07af8b313286f247c78a41a32Chet Haase                }
759d430753cba09acb07af8b313286f247c78a41a32Chet Haase                if (pvh != null) {
760d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    if (values == null) {
761d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        values = new ArrayList<PropertyValuesHolder>();
762d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    }
763d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    values.add(pvh);
764d430753cba09acb07af8b313286f247c78a41a32Chet Haase                }
765d430753cba09acb07af8b313286f247c78a41a32Chet Haase                a.recycle();
766d430753cba09acb07af8b313286f247c78a41a32Chet Haase            }
767d430753cba09acb07af8b313286f247c78a41a32Chet Haase
768d430753cba09acb07af8b313286f247c78a41a32Chet Haase            parser.next();
769d430753cba09acb07af8b313286f247c78a41a32Chet Haase        }
770d430753cba09acb07af8b313286f247c78a41a32Chet Haase
771d430753cba09acb07af8b313286f247c78a41a32Chet Haase        PropertyValuesHolder[] valuesArray = null;
772d430753cba09acb07af8b313286f247c78a41a32Chet Haase        if (values != null) {
773d430753cba09acb07af8b313286f247c78a41a32Chet Haase            int count = values.size();
774d430753cba09acb07af8b313286f247c78a41a32Chet Haase            valuesArray = new PropertyValuesHolder[count];
775d430753cba09acb07af8b313286f247c78a41a32Chet Haase            for (int i = 0; i < count; ++i) {
776d430753cba09acb07af8b313286f247c78a41a32Chet Haase                valuesArray[i] = values.get(i);
777d430753cba09acb07af8b313286f247c78a41a32Chet Haase            }
778d430753cba09acb07af8b313286f247c78a41a32Chet Haase        }
779d430753cba09acb07af8b313286f247c78a41a32Chet Haase        return valuesArray;
780d430753cba09acb07af8b313286f247c78a41a32Chet Haase    }
781d430753cba09acb07af8b313286f247c78a41a32Chet Haase
782d430753cba09acb07af8b313286f247c78a41a32Chet Haase    private static void dumpKeyframes(Object[] keyframes, String header) {
783d430753cba09acb07af8b313286f247c78a41a32Chet Haase        if (keyframes == null || keyframes.length == 0) {
784d430753cba09acb07af8b313286f247c78a41a32Chet Haase            return;
785d430753cba09acb07af8b313286f247c78a41a32Chet Haase        }
786d430753cba09acb07af8b313286f247c78a41a32Chet Haase        Log.d(TAG, header);
787d430753cba09acb07af8b313286f247c78a41a32Chet Haase        int count = keyframes.length;
788d430753cba09acb07af8b313286f247c78a41a32Chet Haase        for (int i = 0; i < count; ++i) {
789d430753cba09acb07af8b313286f247c78a41a32Chet Haase            Keyframe keyframe = (Keyframe) keyframes[i];
790d430753cba09acb07af8b313286f247c78a41a32Chet Haase            Log.d(TAG, "Keyframe " + i + ": fraction " +
791d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    (keyframe.getFraction() < 0 ? "null" : keyframe.getFraction()) + ", " +
792d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    ", value : " + ((keyframe.hasValue()) ? keyframe.getValue() : "null"));
793d430753cba09acb07af8b313286f247c78a41a32Chet Haase        }
794d430753cba09acb07af8b313286f247c78a41a32Chet Haase    }
795d430753cba09acb07af8b313286f247c78a41a32Chet Haase
796d430753cba09acb07af8b313286f247c78a41a32Chet Haase    private static PropertyValuesHolder loadPvh(Resources res, Theme theme, XmlPullParser parser,
797d430753cba09acb07af8b313286f247c78a41a32Chet Haase            String propertyName, int valueType)
798d430753cba09acb07af8b313286f247c78a41a32Chet Haase            throws XmlPullParserException, IOException {
799d430753cba09acb07af8b313286f247c78a41a32Chet Haase
800d430753cba09acb07af8b313286f247c78a41a32Chet Haase        PropertyValuesHolder value = null;
801d430753cba09acb07af8b313286f247c78a41a32Chet Haase        ArrayList<Keyframe> keyframes = null;
802d430753cba09acb07af8b313286f247c78a41a32Chet Haase
803d430753cba09acb07af8b313286f247c78a41a32Chet Haase        int type;
804d430753cba09acb07af8b313286f247c78a41a32Chet Haase        while ((type = parser.next()) != XmlPullParser.END_TAG &&
805d430753cba09acb07af8b313286f247c78a41a32Chet Haase                type != XmlPullParser.END_DOCUMENT) {
806d430753cba09acb07af8b313286f247c78a41a32Chet Haase            String name = parser.getName();
807d430753cba09acb07af8b313286f247c78a41a32Chet Haase            if (name.equals("keyframe")) {
808d430753cba09acb07af8b313286f247c78a41a32Chet Haase                Keyframe keyframe = loadKeyframe(res, theme, Xml.asAttributeSet(parser), valueType);
809d430753cba09acb07af8b313286f247c78a41a32Chet Haase                if (keyframe != null) {
810d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    if (keyframes == null) {
811d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        keyframes = new ArrayList<Keyframe>();
812d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    }
813d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    keyframes.add(keyframe);
814d430753cba09acb07af8b313286f247c78a41a32Chet Haase                }
815d430753cba09acb07af8b313286f247c78a41a32Chet Haase                parser.next();
816d430753cba09acb07af8b313286f247c78a41a32Chet Haase            }
817d430753cba09acb07af8b313286f247c78a41a32Chet Haase        }
818d430753cba09acb07af8b313286f247c78a41a32Chet Haase
819d430753cba09acb07af8b313286f247c78a41a32Chet Haase        int count;
820d430753cba09acb07af8b313286f247c78a41a32Chet Haase        if (keyframes != null && (count = keyframes.size()) > 0) {
821d430753cba09acb07af8b313286f247c78a41a32Chet Haase            // make sure we have keyframes at 0 and 1
822d430753cba09acb07af8b313286f247c78a41a32Chet Haase            // If we have keyframes with set fractions, add keyframes at start/end
823d430753cba09acb07af8b313286f247c78a41a32Chet Haase            // appropriately. If start/end have no set fractions:
824d430753cba09acb07af8b313286f247c78a41a32Chet Haase            // if there's only one keyframe, set its fraction to 1 and add one at 0
825d430753cba09acb07af8b313286f247c78a41a32Chet Haase            // if >1 keyframe, set the last fraction to 1, the first fraction to 0
826d430753cba09acb07af8b313286f247c78a41a32Chet Haase            Keyframe firstKeyframe = keyframes.get(0);
827d430753cba09acb07af8b313286f247c78a41a32Chet Haase            Keyframe lastKeyframe = keyframes.get(count - 1);
828d430753cba09acb07af8b313286f247c78a41a32Chet Haase            float endFraction = lastKeyframe.getFraction();
829d430753cba09acb07af8b313286f247c78a41a32Chet Haase            if (endFraction < 1) {
830d430753cba09acb07af8b313286f247c78a41a32Chet Haase                if (endFraction < 0) {
831d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    lastKeyframe.setFraction(1);
832d430753cba09acb07af8b313286f247c78a41a32Chet Haase                } else {
833d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    keyframes.add(keyframes.size(), createNewKeyframe(lastKeyframe, 1));
834d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    ++count;
835d430753cba09acb07af8b313286f247c78a41a32Chet Haase                }
836d430753cba09acb07af8b313286f247c78a41a32Chet Haase            }
837d430753cba09acb07af8b313286f247c78a41a32Chet Haase            float startFraction = firstKeyframe.getFraction();
838d430753cba09acb07af8b313286f247c78a41a32Chet Haase            if (startFraction != 0) {
839d430753cba09acb07af8b313286f247c78a41a32Chet Haase                if (startFraction < 0) {
840d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    firstKeyframe.setFraction(0);
841d430753cba09acb07af8b313286f247c78a41a32Chet Haase                } else {
842d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    keyframes.add(0, createNewKeyframe(firstKeyframe, 0));
843d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    ++count;
844d430753cba09acb07af8b313286f247c78a41a32Chet Haase                }
845d430753cba09acb07af8b313286f247c78a41a32Chet Haase            }
846d430753cba09acb07af8b313286f247c78a41a32Chet Haase            Keyframe[] keyframeArray = new Keyframe[count];
847d430753cba09acb07af8b313286f247c78a41a32Chet Haase            keyframes.toArray(keyframeArray);
848d430753cba09acb07af8b313286f247c78a41a32Chet Haase            for (int i = 0; i < count; ++i) {
849d430753cba09acb07af8b313286f247c78a41a32Chet Haase                Keyframe keyframe = keyframeArray[i];
850d430753cba09acb07af8b313286f247c78a41a32Chet Haase                if (keyframe.getFraction() < 0) {
851d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    if (i == 0) {
852d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        keyframe.setFraction(0);
853d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    } else if (i == count - 1) {
854d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        keyframe.setFraction(1);
855d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    } else {
856d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        // figure out the start/end parameters of the current gap
857d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        // in fractions and distribute the gap among those keyframes
858d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        int startIndex = i;
859d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        int endIndex = i;
860d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        for (int j = startIndex + 1; j < count - 1; ++j) {
861d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            if (keyframeArray[j].getFraction() >= 0) {
862d430753cba09acb07af8b313286f247c78a41a32Chet Haase                                break;
863d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            }
864d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            endIndex = j;
865d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        }
866d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        float gap = keyframeArray[endIndex + 1].getFraction() -
867d430753cba09acb07af8b313286f247c78a41a32Chet Haase                                keyframeArray[startIndex - 1].getFraction();
868d430753cba09acb07af8b313286f247c78a41a32Chet Haase                        distributeKeyframes(keyframeArray, gap, startIndex, endIndex);
869d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    }
870d430753cba09acb07af8b313286f247c78a41a32Chet Haase                }
871d430753cba09acb07af8b313286f247c78a41a32Chet Haase            }
872d430753cba09acb07af8b313286f247c78a41a32Chet Haase            value = PropertyValuesHolder.ofKeyframe(propertyName, keyframeArray);
873d430753cba09acb07af8b313286f247c78a41a32Chet Haase            if (valueType == VALUE_TYPE_COLOR) {
874d430753cba09acb07af8b313286f247c78a41a32Chet Haase                value.setEvaluator(ArgbEvaluator.getInstance());
875d430753cba09acb07af8b313286f247c78a41a32Chet Haase            }
876d430753cba09acb07af8b313286f247c78a41a32Chet Haase        }
877d430753cba09acb07af8b313286f247c78a41a32Chet Haase
878d430753cba09acb07af8b313286f247c78a41a32Chet Haase        return value;
879d430753cba09acb07af8b313286f247c78a41a32Chet Haase    }
880d430753cba09acb07af8b313286f247c78a41a32Chet Haase
881d430753cba09acb07af8b313286f247c78a41a32Chet Haase    private static Keyframe createNewKeyframe(Keyframe sampleKeyframe, float fraction) {
882d430753cba09acb07af8b313286f247c78a41a32Chet Haase        return sampleKeyframe.getType() == float.class ?
883d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            Keyframe.ofFloat(fraction) :
884d430753cba09acb07af8b313286f247c78a41a32Chet Haase                            (sampleKeyframe.getType() == int.class) ?
885d430753cba09acb07af8b313286f247c78a41a32Chet Haase                                    Keyframe.ofInt(fraction) :
886d430753cba09acb07af8b313286f247c78a41a32Chet Haase                                    Keyframe.ofObject(fraction);
887d430753cba09acb07af8b313286f247c78a41a32Chet Haase    }
888d430753cba09acb07af8b313286f247c78a41a32Chet Haase
889d430753cba09acb07af8b313286f247c78a41a32Chet Haase    /**
890d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * Utility function to set fractions on keyframes to cover a gap in which the
891d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * fractions are not currently set. Keyframe fractions will be distributed evenly
892d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * in this gap. For example, a gap of 1 keyframe in the range 0-1 will be at .5, a gap
893d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * of .6 spread between two keyframes will be at .2 and .4 beyond the fraction at the
894d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * keyframe before startIndex.
895d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * Assumptions:
896d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * - First and last keyframe fractions (bounding this spread) are already set. So,
897d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * for example, if no fractions are set, we will already set first and last keyframe
898d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * fraction values to 0 and 1.
899d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * - startIndex must be >0 (which follows from first assumption).
900d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * - endIndex must be >= startIndex.
901d430753cba09acb07af8b313286f247c78a41a32Chet Haase     *
902d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * @param keyframes the array of keyframes
903d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * @param gap The total gap we need to distribute
904d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * @param startIndex The index of the first keyframe whose fraction must be set
905d430753cba09acb07af8b313286f247c78a41a32Chet Haase     * @param endIndex The index of the last keyframe whose fraction must be set
906d430753cba09acb07af8b313286f247c78a41a32Chet Haase     */
907d430753cba09acb07af8b313286f247c78a41a32Chet Haase    private static void distributeKeyframes(Keyframe[] keyframes, float gap,
908d430753cba09acb07af8b313286f247c78a41a32Chet Haase            int startIndex, int endIndex) {
909d430753cba09acb07af8b313286f247c78a41a32Chet Haase        int count = endIndex - startIndex + 2;
910d430753cba09acb07af8b313286f247c78a41a32Chet Haase        float increment = gap / count;
911d430753cba09acb07af8b313286f247c78a41a32Chet Haase        for (int i = startIndex; i <= endIndex; ++i) {
912d430753cba09acb07af8b313286f247c78a41a32Chet Haase            keyframes[i].setFraction(keyframes[i-1].getFraction() + increment);
913d430753cba09acb07af8b313286f247c78a41a32Chet Haase        }
914d430753cba09acb07af8b313286f247c78a41a32Chet Haase    }
915d430753cba09acb07af8b313286f247c78a41a32Chet Haase
916d430753cba09acb07af8b313286f247c78a41a32Chet Haase    private static Keyframe loadKeyframe(Resources res, Theme theme, AttributeSet attrs,
917d430753cba09acb07af8b313286f247c78a41a32Chet Haase            int valueType)
918d430753cba09acb07af8b313286f247c78a41a32Chet Haase            throws XmlPullParserException, IOException {
919d430753cba09acb07af8b313286f247c78a41a32Chet Haase
920d430753cba09acb07af8b313286f247c78a41a32Chet Haase        TypedArray a;
921d430753cba09acb07af8b313286f247c78a41a32Chet Haase        if (theme != null) {
922d430753cba09acb07af8b313286f247c78a41a32Chet Haase            a = theme.obtainStyledAttributes(attrs, R.styleable.Keyframe, 0, 0);
923d430753cba09acb07af8b313286f247c78a41a32Chet Haase        } else {
924d430753cba09acb07af8b313286f247c78a41a32Chet Haase            a = res.obtainAttributes(attrs, R.styleable.Keyframe);
925d430753cba09acb07af8b313286f247c78a41a32Chet Haase        }
926d430753cba09acb07af8b313286f247c78a41a32Chet Haase
927d430753cba09acb07af8b313286f247c78a41a32Chet Haase        Keyframe keyframe = null;
928d430753cba09acb07af8b313286f247c78a41a32Chet Haase
929d430753cba09acb07af8b313286f247c78a41a32Chet Haase        float fraction = a.getFloat(R.styleable.Keyframe_fraction, -1);
930d430753cba09acb07af8b313286f247c78a41a32Chet Haase
931d430753cba09acb07af8b313286f247c78a41a32Chet Haase        boolean hasValue = a.peekValue(R.styleable.Keyframe_value) != null;
932d430753cba09acb07af8b313286f247c78a41a32Chet Haase
933d430753cba09acb07af8b313286f247c78a41a32Chet Haase        if (hasValue) {
934d430753cba09acb07af8b313286f247c78a41a32Chet Haase            switch (valueType) {
935d430753cba09acb07af8b313286f247c78a41a32Chet Haase                case VALUE_TYPE_FLOAT:
936d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    float value = a.getFloat(R.styleable.Keyframe_value, 0);
937d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    keyframe = Keyframe.ofFloat(fraction, value);
938d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    break;
939d430753cba09acb07af8b313286f247c78a41a32Chet Haase                case VALUE_TYPE_COLOR:
940d430753cba09acb07af8b313286f247c78a41a32Chet Haase                case VALUE_TYPE_INT:
941d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    int intValue = a.getInt(R.styleable.Keyframe_value, 0);
942d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    keyframe = Keyframe.ofInt(fraction, intValue);
943d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    break;
944d430753cba09acb07af8b313286f247c78a41a32Chet Haase            }
945d430753cba09acb07af8b313286f247c78a41a32Chet Haase        } else {
946d430753cba09acb07af8b313286f247c78a41a32Chet Haase            keyframe = (valueType == VALUE_TYPE_FLOAT) ? Keyframe.ofFloat(fraction) :
947d430753cba09acb07af8b313286f247c78a41a32Chet Haase                    Keyframe.ofInt(fraction);
948d430753cba09acb07af8b313286f247c78a41a32Chet Haase        }
949d430753cba09acb07af8b313286f247c78a41a32Chet Haase
9506aac06ab940566020d050fdaa0d5e8d2e6c128aeDoris Liu        final int resID = a.getResourceId(R.styleable.Keyframe_interpolator, 0);
9516aac06ab940566020d050fdaa0d5e8d2e6c128aeDoris Liu        if (resID > 0) {
9526aac06ab940566020d050fdaa0d5e8d2e6c128aeDoris Liu            final Interpolator interpolator = AnimationUtils.loadInterpolator(res, theme, resID);
9536aac06ab940566020d050fdaa0d5e8d2e6c128aeDoris Liu            keyframe.setInterpolator(interpolator);
9546aac06ab940566020d050fdaa0d5e8d2e6c128aeDoris Liu        }
955d430753cba09acb07af8b313286f247c78a41a32Chet Haase        a.recycle();
956e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
957d430753cba09acb07af8b313286f247c78a41a32Chet Haase        return keyframe;
958e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    }
959e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
960fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount    private static ObjectAnimator loadObjectAnimator(Resources res, Theme theme, AttributeSet attrs,
961fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount            float pathErrorScale) throws NotFoundException {
962e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        ObjectAnimator anim = new ObjectAnimator();
963e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
964fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount        loadAnimator(res, theme, attrs, anim, pathErrorScale);
965e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
966e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        return anim;
967e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    }
968e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
969e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    /**
970e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * Creates a new animation whose parameters come from the specified context
971e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * and attributes set.
972e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     *
973e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * @param res The resources
974e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * @param attrs The set of attributes holding the animation parameters
975cf4832f69c8786b098ce18c24319021f8cd6733aztenghui     * @param anim Null if this is a ValueAnimator, otherwise this is an
976cf4832f69c8786b098ce18c24319021f8cd6733aztenghui     *            ObjectAnimator
977e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     */
978e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    private static ValueAnimator loadAnimator(Resources res, Theme theme,
979fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount            AttributeSet attrs, ValueAnimator anim, float pathErrorScale)
980e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            throws NotFoundException {
981cf4832f69c8786b098ce18c24319021f8cd6733aztenghui        TypedArray arrayAnimator = null;
982cf4832f69c8786b098ce18c24319021f8cd6733aztenghui        TypedArray arrayObjectAnimator = null;
983cf4832f69c8786b098ce18c24319021f8cd6733aztenghui
984e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        if (theme != null) {
985cf4832f69c8786b098ce18c24319021f8cd6733aztenghui            arrayAnimator = theme.obtainStyledAttributes(attrs, R.styleable.Animator, 0, 0);
986e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        } else {
987cf4832f69c8786b098ce18c24319021f8cd6733aztenghui            arrayAnimator = res.obtainAttributes(attrs, R.styleable.Animator);
988e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
989e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
990cf4832f69c8786b098ce18c24319021f8cd6733aztenghui        // If anim is not null, then it is an object animator.
991cf4832f69c8786b098ce18c24319021f8cd6733aztenghui        if (anim != null) {
992cf4832f69c8786b098ce18c24319021f8cd6733aztenghui            if (theme != null) {
993cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                arrayObjectAnimator = theme.obtainStyledAttributes(attrs,
994cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                        R.styleable.PropertyAnimator, 0, 0);
995cf4832f69c8786b098ce18c24319021f8cd6733aztenghui            } else {
996cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                arrayObjectAnimator = res.obtainAttributes(attrs, R.styleable.PropertyAnimator);
997cf4832f69c8786b098ce18c24319021f8cd6733aztenghui            }
998d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            anim.appendChangingConfigurations(arrayObjectAnimator.getChangingConfigurations());
999cf4832f69c8786b098ce18c24319021f8cd6733aztenghui        }
10007f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout
10017f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout        if (anim == null) {
10027f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout            anim = new ValueAnimator();
10037f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout        }
1004d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        anim.appendChangingConfigurations(arrayAnimator.getChangingConfigurations());
10057f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout
1006fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount        parseAnimatorFromTypeArray(anim, arrayAnimator, arrayObjectAnimator, pathErrorScale);
1007d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase
1008d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        final int resID = arrayAnimator.getResourceId(R.styleable.Animator_interpolator, 0);
1009d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        if (resID > 0) {
1010d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            final Interpolator interpolator = AnimationUtils.loadInterpolator(res, theme, resID);
1011d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            if (interpolator instanceof BaseInterpolator) {
1012d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                anim.appendChangingConfigurations(
1013d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                        ((BaseInterpolator) interpolator).getChangingConfiguration());
1014d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            }
1015d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            anim.setInterpolator(interpolator);
1016d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        }
1017cf4832f69c8786b098ce18c24319021f8cd6733aztenghui
1018cf4832f69c8786b098ce18c24319021f8cd6733aztenghui        arrayAnimator.recycle();
10197f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout        if (arrayObjectAnimator != null) {
10207f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout            arrayObjectAnimator.recycle();
10217f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout        }
1022d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        return anim;
1023d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase    }
1024d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar
1025d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar    private static int getChangingConfigs(Resources resources, int id) {
1026d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        synchronized (sTmpTypedValue) {
1027d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            resources.getValue(id, sTmpTypedValue, true);
1028d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            return sTmpTypedValue.changingConfigurations;
1029d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        }
1030d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar    }
1031d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase}
1032