AnimatorInflater.java revision fd3c4744f265c5277e6e2641a18d5ec3dff19f6b
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
18d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.content.Context;
19d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.content.res.Resources;
20cf4832f69c8786b098ce18c24319021f8cd6733aztenghuiimport android.content.res.Resources.NotFoundException;
21e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghuiimport android.content.res.Resources.Theme;
22d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.content.res.TypedArray;
23d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.content.res.XmlResourceParser;
24cf4832f69c8786b098ce18c24319021f8cd6733aztenghuiimport android.graphics.Path;
25d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.util.AttributeSet;
26eb034fbca40006c55db143047eb628c4b657730aztenghuiimport android.util.Log;
27cf4832f69c8786b098ce18c24319021f8cd6733aztenghuiimport android.util.PathParser;
28f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyarimport android.util.StateSet;
295bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haaseimport android.util.TypedValue;
30d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.util.Xml;
31eb034fbca40006c55db143047eb628c4b657730aztenghuiimport android.view.InflateException;
32d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport android.view.animation.AnimationUtils;
33e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
34e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghuiimport com.android.internal.R;
35e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
36d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport org.xmlpull.v1.XmlPullParser;
37d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport org.xmlpull.v1.XmlPullParserException;
38d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase
39d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport java.io.IOException;
40d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haaseimport java.util.ArrayList;
41d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase
42d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase/**
436cfdf4538049e4b96f50d8c0fe3119664420cc34Chet Haase * This class is used to instantiate animator XML files into Animator objects.
44d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * <p>
456cfdf4538049e4b96f50d8c0fe3119664420cc34Chet Haase * For performance reasons, inflation relies heavily on pre-processing of
46d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * XML files that is done at build time. Therefore, it is not currently possible
476cfdf4538049e4b96f50d8c0fe3119664420cc34Chet Haase * to use this inflater with an XmlPullParser over a plain XML file at runtime;
48d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * it only works with an XmlPullParser returned from a compiled resource (R.
49d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase * <em>something</em> file.)
50d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase */
51a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haasepublic class AnimatorInflater {
52eb034fbca40006c55db143047eb628c4b657730aztenghui    private static final String TAG = "AnimatorInflater";
53d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase    /**
54a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * These flags are used when parsing AnimatorSet objects
55d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase     */
56d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase    private static final int TOGETHER = 0;
57d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase    private static final int SEQUENTIALLY = 1;
58d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase
59d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase    /**
60d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase     * Enum values used in XML attributes to indicate the value for mValueType
61d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase     */
62d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase    private static final int VALUE_TYPE_FLOAT       = 0;
63d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase    private static final int VALUE_TYPE_INT         = 1;
64eb034fbca40006c55db143047eb628c4b657730aztenghui    private static final int VALUE_TYPE_PATH        = 2;
652794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    private static final int VALUE_TYPE_COLOR       = 4;
662794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    private static final int VALUE_TYPE_CUSTOM      = 5;
67d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase
68eb034fbca40006c55db143047eb628c4b657730aztenghui    private static final boolean DBG_ANIMATOR_INFLATER = false;
69eb034fbca40006c55db143047eb628c4b657730aztenghui
70d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase    /**
71a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Loads an {@link Animator} object from a resource
72d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase     *
73d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase     * @param context Application context used to access resources
74d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase     * @param id The resource id of the animation to load
75a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * @return The animator object reference by the specified id
76d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase     * @throws android.content.res.Resources.NotFoundException when the animation cannot be loaded
77d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase     */
78a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    public static Animator loadAnimator(Context context, int id)
79d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase            throws NotFoundException {
80e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        return loadAnimator(context.getResources(), context.getTheme(), id);
81e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    }
82e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
83e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    /**
84e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * Loads an {@link Animator} object from a resource
85e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     *
86e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * @param resources The resources
87e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * @param theme The theme
88e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * @param id The resource id of the animation to load
89e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * @return The animator object reference by the specified id
90e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * @throws android.content.res.Resources.NotFoundException when the animation cannot be loaded
91e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * @hide
92e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     */
93e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    public static Animator loadAnimator(Resources resources, Theme theme, int id)
94e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            throws NotFoundException {
95fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount        return loadAnimator(resources, theme, id, 1);
96fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount    }
97fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount
98fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount    /** @hide */
99fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount    public static Animator loadAnimator(Resources resources, Theme theme, int id,
100fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount            float pathErrorScale) throws NotFoundException {
101d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase
102d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        XmlResourceParser parser = null;
103d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        try {
104e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            parser = resources.getAnimation(id);
105fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount            return createAnimatorFromXml(resources, theme, parser, pathErrorScale);
106d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        } catch (XmlPullParserException ex) {
107d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase            Resources.NotFoundException rnf =
108d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase                    new Resources.NotFoundException("Can't load animation resource ID #0x" +
109fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount                            Integer.toHexString(id));
110d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase            rnf.initCause(ex);
111d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase            throw rnf;
112d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        } catch (IOException ex) {
113d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase            Resources.NotFoundException rnf =
114d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase                    new Resources.NotFoundException("Can't load animation resource ID #0x" +
115fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount                            Integer.toHexString(id));
116d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase            rnf.initCause(ex);
117d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase            throw rnf;
118d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        } finally {
119d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase            if (parser != null) parser.close();
120d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        }
121d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase    }
122d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase
123f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar    public static StateListAnimator loadStateListAnimator(Context context, int id)
124f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            throws NotFoundException {
125f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        XmlResourceParser parser = null;
126f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        try {
127f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            parser = context.getResources().getAnimation(id);
128f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            return createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser));
129f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        } catch (XmlPullParserException ex) {
130f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            Resources.NotFoundException rnf =
131f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    new Resources.NotFoundException(
132f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                            "Can't load state list animator resource ID #0x" +
133f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                                    Integer.toHexString(id)
134f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    );
135f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            rnf.initCause(ex);
136f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            throw rnf;
137f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        } catch (IOException ex) {
138f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            Resources.NotFoundException rnf =
139f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    new Resources.NotFoundException(
140f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                            "Can't load state list animator resource ID #0x" +
141f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                                    Integer.toHexString(id)
142f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    );
143f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            rnf.initCause(ex);
144f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            throw rnf;
145f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        } finally {
146f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            if (parser != null) {
147f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                parser.close();
148f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            }
149f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        }
150f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar    }
151f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar
152f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar    private static StateListAnimator createStateListAnimatorFromXml(Context context,
153f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            XmlPullParser parser, AttributeSet attributeSet)
154f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            throws IOException, XmlPullParserException {
155f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        int type;
156f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        StateListAnimator stateListAnimator = new StateListAnimator();
157f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar
158f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        while (true) {
159f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            type = parser.next();
160f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            switch (type) {
161f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                case XmlPullParser.END_DOCUMENT:
162f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                case XmlPullParser.END_TAG:
163f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    return stateListAnimator;
164f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar
165f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                case XmlPullParser.START_TAG:
166f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    // parse item
167f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    Animator animator = null;
168f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    if ("item".equals(parser.getName())) {
169f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        int attributeCount = parser.getAttributeCount();
170f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        int[] states = new int[attributeCount];
171f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        int stateIndex = 0;
172f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        for (int i = 0; i < attributeCount; i++) {
173f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                            int attrName = attributeSet.getAttributeNameResource(i);
174cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                            if (attrName == R.attr.animation) {
175f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                                animator = loadAnimator(context,
176f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                                        attributeSet.getAttributeResourceValue(i, 0));
177f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                            } else {
178f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                                states[stateIndex++] =
179f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                                        attributeSet.getAttributeBooleanValue(i, false) ?
180f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                                                attrName : -attrName;
181f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                            }
182f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar
183f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        }
184f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        if (animator == null) {
185e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                            animator = createAnimatorFromXml(context.getResources(),
186fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount                                    context.getTheme(), parser, 1f);
187f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        }
188f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar
189f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        if (animator == null) {
190f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                            throw new Resources.NotFoundException(
191f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                                    "animation state item must have a valid animation");
192f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        }
193f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                        stateListAnimator
194f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                                .addState(StateSet.trimStateSet(states, stateIndex), animator);
195f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar
196f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    }
197f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar                    break;
198f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar            }
199f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar        }
200f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar    }
201f4c5bf30b445874cf353e1b96cab94185a39ce6dYigit Boyar
202cf4832f69c8786b098ce18c24319021f8cd6733aztenghui    /**
203eb034fbca40006c55db143047eb628c4b657730aztenghui     * PathDataEvaluator is used to interpolate between two paths which are
204eb034fbca40006c55db143047eb628c4b657730aztenghui     * represented in the same format but different control points' values.
205eb034fbca40006c55db143047eb628c4b657730aztenghui     * The path is represented as an array of PathDataNode here, which is
206eb034fbca40006c55db143047eb628c4b657730aztenghui     * fundamentally an array of floating point numbers.
207eb034fbca40006c55db143047eb628c4b657730aztenghui     */
208eb034fbca40006c55db143047eb628c4b657730aztenghui    private static class PathDataEvaluator implements TypeEvaluator<PathParser.PathDataNode[]> {
209eb034fbca40006c55db143047eb628c4b657730aztenghui        private PathParser.PathDataNode[] mNodeArray;
210eb034fbca40006c55db143047eb628c4b657730aztenghui
211eb034fbca40006c55db143047eb628c4b657730aztenghui        /**
212eb034fbca40006c55db143047eb628c4b657730aztenghui         * Create a PathParser.PathDataNode[] that does not reuse the animated value.
213eb034fbca40006c55db143047eb628c4b657730aztenghui         * Care must be taken when using this option because on every evaluation
214eb034fbca40006c55db143047eb628c4b657730aztenghui         * a new <code>PathParser.PathDataNode[]</code> will be allocated.
215eb034fbca40006c55db143047eb628c4b657730aztenghui         */
216eb034fbca40006c55db143047eb628c4b657730aztenghui        private PathDataEvaluator() {}
217eb034fbca40006c55db143047eb628c4b657730aztenghui
218eb034fbca40006c55db143047eb628c4b657730aztenghui        /**
219eb034fbca40006c55db143047eb628c4b657730aztenghui         * Create a PathDataEvaluator that reuses <code>nodeArray</code> for every evaluate() call.
220eb034fbca40006c55db143047eb628c4b657730aztenghui         * Caution must be taken to ensure that the value returned from
221eb034fbca40006c55db143047eb628c4b657730aztenghui         * {@link android.animation.ValueAnimator#getAnimatedValue()} is not cached, modified, or
222eb034fbca40006c55db143047eb628c4b657730aztenghui         * used across threads. The value will be modified on each <code>evaluate()</code> call.
223eb034fbca40006c55db143047eb628c4b657730aztenghui         *
224eb034fbca40006c55db143047eb628c4b657730aztenghui         * @param nodeArray The array to modify and return from <code>evaluate</code>.
225eb034fbca40006c55db143047eb628c4b657730aztenghui         */
226eb034fbca40006c55db143047eb628c4b657730aztenghui        public PathDataEvaluator(PathParser.PathDataNode[] nodeArray) {
227eb034fbca40006c55db143047eb628c4b657730aztenghui            mNodeArray = nodeArray;
228eb034fbca40006c55db143047eb628c4b657730aztenghui        }
229eb034fbca40006c55db143047eb628c4b657730aztenghui
230eb034fbca40006c55db143047eb628c4b657730aztenghui        @Override
231eb034fbca40006c55db143047eb628c4b657730aztenghui        public PathParser.PathDataNode[] evaluate(float fraction,
232eb034fbca40006c55db143047eb628c4b657730aztenghui                PathParser.PathDataNode[] startPathData,
233eb034fbca40006c55db143047eb628c4b657730aztenghui                PathParser.PathDataNode[] endPathData) {
234eb034fbca40006c55db143047eb628c4b657730aztenghui            if (!PathParser.canMorph(startPathData, endPathData)) {
235eb034fbca40006c55db143047eb628c4b657730aztenghui                throw new IllegalArgumentException("Can't interpolate between"
236eb034fbca40006c55db143047eb628c4b657730aztenghui                        + " two incompatible pathData");
237eb034fbca40006c55db143047eb628c4b657730aztenghui            }
238eb034fbca40006c55db143047eb628c4b657730aztenghui
239eb034fbca40006c55db143047eb628c4b657730aztenghui            if (mNodeArray == null || !PathParser.canMorph(mNodeArray, startPathData)) {
240eb034fbca40006c55db143047eb628c4b657730aztenghui                mNodeArray = PathParser.deepCopyNodes(startPathData);
241eb034fbca40006c55db143047eb628c4b657730aztenghui            }
242eb034fbca40006c55db143047eb628c4b657730aztenghui
243eb034fbca40006c55db143047eb628c4b657730aztenghui            for (int i = 0; i < startPathData.length; i++) {
244eb034fbca40006c55db143047eb628c4b657730aztenghui                mNodeArray[i].interpolatePathDataNode(startPathData[i],
245eb034fbca40006c55db143047eb628c4b657730aztenghui                        endPathData[i], fraction);
246eb034fbca40006c55db143047eb628c4b657730aztenghui            }
247eb034fbca40006c55db143047eb628c4b657730aztenghui
248eb034fbca40006c55db143047eb628c4b657730aztenghui            return mNodeArray;
249eb034fbca40006c55db143047eb628c4b657730aztenghui        }
250eb034fbca40006c55db143047eb628c4b657730aztenghui    }
251eb034fbca40006c55db143047eb628c4b657730aztenghui
252eb034fbca40006c55db143047eb628c4b657730aztenghui    /**
2537f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout     * @param anim The animator, must not be null
254cf4832f69c8786b098ce18c24319021f8cd6733aztenghui     * @param arrayAnimator Incoming typed array for Animator's attributes.
255cf4832f69c8786b098ce18c24319021f8cd6733aztenghui     * @param arrayObjectAnimator Incoming typed array for Object Animator's
256cf4832f69c8786b098ce18c24319021f8cd6733aztenghui     *            attributes.
257fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount     * @param pixelSize The relative pixel size, used to calculate the
258fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount     *                  maximum error for path animations.
259cf4832f69c8786b098ce18c24319021f8cd6733aztenghui     */
260cf4832f69c8786b098ce18c24319021f8cd6733aztenghui    private static void parseAnimatorFromTypeArray(ValueAnimator anim,
261fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount            TypedArray arrayAnimator, TypedArray arrayObjectAnimator, float pixelSize) {
262cf4832f69c8786b098ce18c24319021f8cd6733aztenghui        long duration = arrayAnimator.getInt(R.styleable.Animator_duration, 300);
263d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase
264cf4832f69c8786b098ce18c24319021f8cd6733aztenghui        long startDelay = arrayAnimator.getInt(R.styleable.Animator_startOffset, 0);
265d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase
266cf4832f69c8786b098ce18c24319021f8cd6733aztenghui        int valueType = arrayAnimator.getInt(R.styleable.Animator_valueType,
267d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase                VALUE_TYPE_FLOAT);
268d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase
269cf4832f69c8786b098ce18c24319021f8cd6733aztenghui        TypeEvaluator evaluator = null;
2705bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase
2715bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase        boolean getFloats = (valueType == VALUE_TYPE_FLOAT);
2725bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase
273eb034fbca40006c55db143047eb628c4b657730aztenghui        TypedValue tvFrom = arrayAnimator.peekValue(R.styleable.Animator_valueFrom);
2745bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase        boolean hasFrom = (tvFrom != null);
2755bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase        int fromType = hasFrom ? tvFrom.type : 0;
276eb034fbca40006c55db143047eb628c4b657730aztenghui        TypedValue tvTo = arrayAnimator.peekValue(R.styleable.Animator_valueTo);
2775bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase        boolean hasTo = (tvTo != null);
2785bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase        int toType = hasTo ? tvTo.type : 0;
2795bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase
280eb034fbca40006c55db143047eb628c4b657730aztenghui        // TODO: Further clean up this part of code into 4 types : path, color,
281eb034fbca40006c55db143047eb628c4b657730aztenghui        // integer and float.
282eb034fbca40006c55db143047eb628c4b657730aztenghui        if (valueType == VALUE_TYPE_PATH) {
283eb034fbca40006c55db143047eb628c4b657730aztenghui            evaluator = setupAnimatorForPath(anim, arrayAnimator);
284eb034fbca40006c55db143047eb628c4b657730aztenghui        } else {
285eb034fbca40006c55db143047eb628c4b657730aztenghui            // Integer and float value types are handled here.
286eb034fbca40006c55db143047eb628c4b657730aztenghui            if ((hasFrom && (fromType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
287eb034fbca40006c55db143047eb628c4b657730aztenghui                    (fromType <= TypedValue.TYPE_LAST_COLOR_INT)) ||
288eb034fbca40006c55db143047eb628c4b657730aztenghui                    (hasTo && (toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
289eb034fbca40006c55db143047eb628c4b657730aztenghui                            (toType <= TypedValue.TYPE_LAST_COLOR_INT))) {
290eb034fbca40006c55db143047eb628c4b657730aztenghui                // special case for colors: ignore valueType and get ints
291eb034fbca40006c55db143047eb628c4b657730aztenghui                getFloats = false;
292eb034fbca40006c55db143047eb628c4b657730aztenghui                evaluator = ArgbEvaluator.getInstance();
293eb034fbca40006c55db143047eb628c4b657730aztenghui            }
294eb034fbca40006c55db143047eb628c4b657730aztenghui            setupValues(anim, arrayAnimator, getFloats, hasFrom, fromType, hasTo, toType);
2955bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase        }
2965bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase
297eb034fbca40006c55db143047eb628c4b657730aztenghui        anim.setDuration(duration);
298eb034fbca40006c55db143047eb628c4b657730aztenghui        anim.setStartDelay(startDelay);
299eb034fbca40006c55db143047eb628c4b657730aztenghui
300eb034fbca40006c55db143047eb628c4b657730aztenghui        if (arrayAnimator.hasValue(R.styleable.Animator_repeatCount)) {
301eb034fbca40006c55db143047eb628c4b657730aztenghui            anim.setRepeatCount(
302eb034fbca40006c55db143047eb628c4b657730aztenghui                    arrayAnimator.getInt(R.styleable.Animator_repeatCount, 0));
303eb034fbca40006c55db143047eb628c4b657730aztenghui        }
304eb034fbca40006c55db143047eb628c4b657730aztenghui        if (arrayAnimator.hasValue(R.styleable.Animator_repeatMode)) {
305eb034fbca40006c55db143047eb628c4b657730aztenghui            anim.setRepeatMode(
306eb034fbca40006c55db143047eb628c4b657730aztenghui                    arrayAnimator.getInt(R.styleable.Animator_repeatMode,
307eb034fbca40006c55db143047eb628c4b657730aztenghui                            ValueAnimator.RESTART));
308eb034fbca40006c55db143047eb628c4b657730aztenghui        }
309eb034fbca40006c55db143047eb628c4b657730aztenghui        if (evaluator != null) {
310eb034fbca40006c55db143047eb628c4b657730aztenghui            anim.setEvaluator(evaluator);
311eb034fbca40006c55db143047eb628c4b657730aztenghui        }
312eb034fbca40006c55db143047eb628c4b657730aztenghui
313eb034fbca40006c55db143047eb628c4b657730aztenghui        if (arrayObjectAnimator != null) {
314fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount            setupObjectAnimator(anim, arrayObjectAnimator, getFloats, pixelSize);
315eb034fbca40006c55db143047eb628c4b657730aztenghui        }
316eb034fbca40006c55db143047eb628c4b657730aztenghui    }
317eb034fbca40006c55db143047eb628c4b657730aztenghui
318eb034fbca40006c55db143047eb628c4b657730aztenghui    /**
319eb034fbca40006c55db143047eb628c4b657730aztenghui     * Setup the Animator to achieve path morphing.
320eb034fbca40006c55db143047eb628c4b657730aztenghui     *
321eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param anim The target Animator which will be updated.
322eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param arrayAnimator TypedArray for the ValueAnimator.
323eb034fbca40006c55db143047eb628c4b657730aztenghui     * @return the PathDataEvaluator.
324eb034fbca40006c55db143047eb628c4b657730aztenghui     */
325eb034fbca40006c55db143047eb628c4b657730aztenghui    private static TypeEvaluator setupAnimatorForPath(ValueAnimator anim,
326eb034fbca40006c55db143047eb628c4b657730aztenghui             TypedArray arrayAnimator) {
327eb034fbca40006c55db143047eb628c4b657730aztenghui        TypeEvaluator evaluator = null;
328eb034fbca40006c55db143047eb628c4b657730aztenghui        String fromString = arrayAnimator.getString(R.styleable.Animator_valueFrom);
329eb034fbca40006c55db143047eb628c4b657730aztenghui        String toString = arrayAnimator.getString(R.styleable.Animator_valueTo);
330eb034fbca40006c55db143047eb628c4b657730aztenghui        PathParser.PathDataNode[] nodesFrom = PathParser.createNodesFromPathData(fromString);
331eb034fbca40006c55db143047eb628c4b657730aztenghui        PathParser.PathDataNode[] nodesTo = PathParser.createNodesFromPathData(toString);
332eb034fbca40006c55db143047eb628c4b657730aztenghui
333eb034fbca40006c55db143047eb628c4b657730aztenghui        if (nodesFrom != null) {
334eb034fbca40006c55db143047eb628c4b657730aztenghui            if (nodesTo != null) {
335eb034fbca40006c55db143047eb628c4b657730aztenghui                anim.setObjectValues(nodesFrom, nodesTo);
336eb034fbca40006c55db143047eb628c4b657730aztenghui                if (!PathParser.canMorph(nodesFrom, nodesTo)) {
337eb034fbca40006c55db143047eb628c4b657730aztenghui                    throw new InflateException(arrayAnimator.getPositionDescription()
338eb034fbca40006c55db143047eb628c4b657730aztenghui                            + " Can't morph from " + fromString + " to " + toString);
339eb034fbca40006c55db143047eb628c4b657730aztenghui                }
340eb034fbca40006c55db143047eb628c4b657730aztenghui            } else {
341eb034fbca40006c55db143047eb628c4b657730aztenghui                anim.setObjectValues((Object)nodesFrom);
342eb034fbca40006c55db143047eb628c4b657730aztenghui            }
343eb034fbca40006c55db143047eb628c4b657730aztenghui            evaluator = new PathDataEvaluator(PathParser.deepCopyNodes(nodesFrom));
344eb034fbca40006c55db143047eb628c4b657730aztenghui        } else if (nodesTo != null) {
345eb034fbca40006c55db143047eb628c4b657730aztenghui            anim.setObjectValues((Object)nodesTo);
346eb034fbca40006c55db143047eb628c4b657730aztenghui            evaluator = new PathDataEvaluator(PathParser.deepCopyNodes(nodesTo));
347eb034fbca40006c55db143047eb628c4b657730aztenghui        }
348eb034fbca40006c55db143047eb628c4b657730aztenghui
349eb034fbca40006c55db143047eb628c4b657730aztenghui        if (DBG_ANIMATOR_INFLATER && evaluator != null) {
350eb034fbca40006c55db143047eb628c4b657730aztenghui            Log.v(TAG, "create a new PathDataEvaluator here");
351eb034fbca40006c55db143047eb628c4b657730aztenghui        }
352eb034fbca40006c55db143047eb628c4b657730aztenghui
353eb034fbca40006c55db143047eb628c4b657730aztenghui        return evaluator;
354eb034fbca40006c55db143047eb628c4b657730aztenghui    }
355eb034fbca40006c55db143047eb628c4b657730aztenghui
356eb034fbca40006c55db143047eb628c4b657730aztenghui    /**
357eb034fbca40006c55db143047eb628c4b657730aztenghui     * Setup ObjectAnimator's property or values from pathData.
358eb034fbca40006c55db143047eb628c4b657730aztenghui     *
359eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param anim The target Animator which will be updated.
360eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param arrayObjectAnimator TypedArray for the ObjectAnimator.
361eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param getFloats True if the value type is float.
362fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount     * @param pixelSize The relative pixel size, used to calculate the
363fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount     *                  maximum error for path animations.
364eb034fbca40006c55db143047eb628c4b657730aztenghui     */
365eb034fbca40006c55db143047eb628c4b657730aztenghui    private static void setupObjectAnimator(ValueAnimator anim, TypedArray arrayObjectAnimator,
366fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount            boolean getFloats, float pixelSize) {
367eb034fbca40006c55db143047eb628c4b657730aztenghui        ObjectAnimator oa = (ObjectAnimator) anim;
368eb034fbca40006c55db143047eb628c4b657730aztenghui        String pathData = arrayObjectAnimator.getString(R.styleable.PropertyAnimator_pathData);
369eb034fbca40006c55db143047eb628c4b657730aztenghui
370eb034fbca40006c55db143047eb628c4b657730aztenghui        // Note that if there is a pathData defined in the Object Animator,
371eb034fbca40006c55db143047eb628c4b657730aztenghui        // valueFrom / valueTo will be ignored.
372eb034fbca40006c55db143047eb628c4b657730aztenghui        if (pathData != null) {
373eb034fbca40006c55db143047eb628c4b657730aztenghui            String propertyXName =
374eb034fbca40006c55db143047eb628c4b657730aztenghui                    arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyXName);
375eb034fbca40006c55db143047eb628c4b657730aztenghui            String propertyYName =
376eb034fbca40006c55db143047eb628c4b657730aztenghui                    arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyYName);
377eb034fbca40006c55db143047eb628c4b657730aztenghui
378eb034fbca40006c55db143047eb628c4b657730aztenghui            if (propertyXName == null && propertyYName == null) {
379eb034fbca40006c55db143047eb628c4b657730aztenghui                throw new InflateException(arrayObjectAnimator.getPositionDescription()
380eb034fbca40006c55db143047eb628c4b657730aztenghui                        + " propertyXName or propertyYName is needed for PathData");
381eb034fbca40006c55db143047eb628c4b657730aztenghui            } else {
382eb034fbca40006c55db143047eb628c4b657730aztenghui                Path path = PathParser.createPathFromPathData(pathData);
383fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount                float error = 0.5f * pixelSize; // max half a pixel error
384fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount                PathKeyframes keyframeSet = KeyframeSet.ofPath(path, error);
385984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                Keyframes xKeyframes;
386984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                Keyframes yKeyframes;
387984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                if (getFloats) {
388984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                    xKeyframes = keyframeSet.createXFloatKeyframes();
389984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                    yKeyframes = keyframeSet.createYFloatKeyframes();
390984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                } else {
391984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                    xKeyframes = keyframeSet.createXIntKeyframes();
392984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                    yKeyframes = keyframeSet.createYIntKeyframes();
393984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                }
394eb034fbca40006c55db143047eb628c4b657730aztenghui                PropertyValuesHolder x = null;
395eb034fbca40006c55db143047eb628c4b657730aztenghui                PropertyValuesHolder y = null;
396eb034fbca40006c55db143047eb628c4b657730aztenghui                if (propertyXName != null) {
397984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                    x = PropertyValuesHolder.ofKeyframes(propertyXName, xKeyframes);
398eb034fbca40006c55db143047eb628c4b657730aztenghui                }
399eb034fbca40006c55db143047eb628c4b657730aztenghui                if (propertyYName != null) {
400984011f6850fd4b6ad4db6d6022bd475d7a2c712George Mount                    y = PropertyValuesHolder.ofKeyframes(propertyYName, yKeyframes);
401eb034fbca40006c55db143047eb628c4b657730aztenghui                }
402eb034fbca40006c55db143047eb628c4b657730aztenghui                if (x == null) {
403eb034fbca40006c55db143047eb628c4b657730aztenghui                    oa.setValues(y);
404eb034fbca40006c55db143047eb628c4b657730aztenghui                } else if (y == null) {
405eb034fbca40006c55db143047eb628c4b657730aztenghui                    oa.setValues(x);
406eb034fbca40006c55db143047eb628c4b657730aztenghui                } else {
407eb034fbca40006c55db143047eb628c4b657730aztenghui                    oa.setValues(x, y);
408eb034fbca40006c55db143047eb628c4b657730aztenghui                }
409eb034fbca40006c55db143047eb628c4b657730aztenghui            }
410eb034fbca40006c55db143047eb628c4b657730aztenghui        } else {
411eb034fbca40006c55db143047eb628c4b657730aztenghui            String propertyName =
412eb034fbca40006c55db143047eb628c4b657730aztenghui                    arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyName);
413eb034fbca40006c55db143047eb628c4b657730aztenghui            oa.setPropertyName(propertyName);
414eb034fbca40006c55db143047eb628c4b657730aztenghui        }
415eb034fbca40006c55db143047eb628c4b657730aztenghui    }
416eb034fbca40006c55db143047eb628c4b657730aztenghui
417eb034fbca40006c55db143047eb628c4b657730aztenghui    /**
418eb034fbca40006c55db143047eb628c4b657730aztenghui     * Setup ValueAnimator's values.
419eb034fbca40006c55db143047eb628c4b657730aztenghui     * This will handle all of the integer, float and color types.
420eb034fbca40006c55db143047eb628c4b657730aztenghui     *
421eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param anim The target Animator which will be updated.
422eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param arrayAnimator TypedArray for the ValueAnimator.
423eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param getFloats True if the value type is float.
424eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param hasFrom True if "valueFrom" exists.
425eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param fromType The type of "valueFrom".
426eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param hasTo True if "valueTo" exists.
427eb034fbca40006c55db143047eb628c4b657730aztenghui     * @param toType The type of "valueTo".
428eb034fbca40006c55db143047eb628c4b657730aztenghui     */
429eb034fbca40006c55db143047eb628c4b657730aztenghui    private static void setupValues(ValueAnimator anim, TypedArray arrayAnimator,
430eb034fbca40006c55db143047eb628c4b657730aztenghui            boolean getFloats, boolean hasFrom, int fromType, boolean hasTo, int toType) {
431eb034fbca40006c55db143047eb628c4b657730aztenghui        int valueFromIndex = R.styleable.Animator_valueFrom;
432eb034fbca40006c55db143047eb628c4b657730aztenghui        int valueToIndex = R.styleable.Animator_valueTo;
4335bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase        if (getFloats) {
4345bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase            float valueFrom;
4355bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase            float valueTo;
4365bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase            if (hasFrom) {
4375bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                if (fromType == TypedValue.TYPE_DIMENSION) {
438cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                    valueFrom = arrayAnimator.getDimension(valueFromIndex, 0f);
4395bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                } else {
440cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                    valueFrom = arrayAnimator.getFloat(valueFromIndex, 0f);
4415bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                }
4425bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                if (hasTo) {
4435bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    if (toType == TypedValue.TYPE_DIMENSION) {
444cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                        valueTo = arrayAnimator.getDimension(valueToIndex, 0f);
4452794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase                    } else {
446cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                        valueTo = arrayAnimator.getFloat(valueToIndex, 0f);
4472794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase                    }
4485bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    anim.setFloatValues(valueFrom, valueTo);
4495bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                } else {
4505bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    anim.setFloatValues(valueFrom);
4515bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                }
4525bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase            } else {
4535bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                if (toType == TypedValue.TYPE_DIMENSION) {
454cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                    valueTo = arrayAnimator.getDimension(valueToIndex, 0f);
4552794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase                } else {
456cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                    valueTo = arrayAnimator.getFloat(valueToIndex, 0f);
457d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase                }
4585bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                anim.setFloatValues(valueTo);
4592794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase            }
4605bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase        } else {
4615bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase            int valueFrom;
4625bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase            int valueTo;
4635bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase            if (hasFrom) {
4645bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                if (fromType == TypedValue.TYPE_DIMENSION) {
465cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                    valueFrom = (int) arrayAnimator.getDimension(valueFromIndex, 0f);
4665bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                } else if ((fromType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
4675bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                        (fromType <= TypedValue.TYPE_LAST_COLOR_INT)) {
468cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                    valueFrom = arrayAnimator.getColor(valueFromIndex, 0);
4695bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                } else {
470cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                    valueFrom = arrayAnimator.getInt(valueFromIndex, 0);
4715bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                }
4725bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                if (hasTo) {
4735bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    if (toType == TypedValue.TYPE_DIMENSION) {
474cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                        valueTo = (int) arrayAnimator.getDimension(valueToIndex, 0f);
4755bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    } else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
4765bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                            (toType <= TypedValue.TYPE_LAST_COLOR_INT)) {
477cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                        valueTo = arrayAnimator.getColor(valueToIndex, 0);
4782794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase                    } else {
479cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                        valueTo = arrayAnimator.getInt(valueToIndex, 0);
4802794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase                    }
4815bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    anim.setIntValues(valueFrom, valueTo);
4822794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase                } else {
4835bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    anim.setIntValues(valueFrom);
484d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase                }
4855bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase            } else {
4865bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                if (hasTo) {
4875bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    if (toType == TypedValue.TYPE_DIMENSION) {
488cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                        valueTo = (int) arrayAnimator.getDimension(valueToIndex, 0f);
4895bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    } else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
490cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                            (toType <= TypedValue.TYPE_LAST_COLOR_INT)) {
491cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                        valueTo = arrayAnimator.getColor(valueToIndex, 0);
4922794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase                    } else {
493cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                        valueTo = arrayAnimator.getInt(valueToIndex, 0);
4942794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase                    }
4955bed88e12d0b4e77483e287c068fbf551ecf8a10Chet Haase                    anim.setIntValues(valueTo);
496d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase                }
4972794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase            }
498d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        }
499e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    }
500e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
501fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount    private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser,
502fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount            float pixelSize)
503e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            throws XmlPullParserException, IOException {
504fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount        return createAnimatorFromXml(res, theme, parser, Xml.asAttributeSet(parser), null, 0,
505fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount                pixelSize);
506e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    }
507e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
508e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser,
509fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount            AttributeSet attrs, AnimatorSet parent, int sequenceOrdering, float pixelSize)
510e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            throws XmlPullParserException, IOException {
511e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
512e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        Animator anim = null;
513e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        ArrayList<Animator> childAnims = null;
514e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
515e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        // Make sure we are on a start tag.
516e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        int type;
517e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        int depth = parser.getDepth();
518e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
519e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
520e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                && type != XmlPullParser.END_DOCUMENT) {
521e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
522e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            if (type != XmlPullParser.START_TAG) {
523e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                continue;
524e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            }
525e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
526e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            String name = parser.getName();
527e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
528e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            if (name.equals("objectAnimator")) {
529fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount                anim = loadObjectAnimator(res, theme, attrs, pixelSize);
530e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            } else if (name.equals("animator")) {
531fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount                anim = loadAnimator(res, theme, attrs, null, pixelSize);
532e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            } else if (name.equals("set")) {
533e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                anim = new AnimatorSet();
534e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                TypedArray a;
535e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                if (theme != null) {
536cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                    a = theme.obtainStyledAttributes(attrs, R.styleable.AnimatorSet, 0, 0);
537e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                } else {
538cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                    a = res.obtainAttributes(attrs, R.styleable.AnimatorSet);
539e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                }
540cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                int ordering = a.getInt(R.styleable.AnimatorSet_ordering,
541e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                        TOGETHER);
542fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount                createAnimatorFromXml(res, theme, parser, attrs, (AnimatorSet) anim, ordering,
543fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount                        pixelSize);
544e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                a.recycle();
545e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            } else {
546e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                throw new RuntimeException("Unknown animator name: " + parser.getName());
547e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            }
548e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
549e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            if (parent != null) {
550e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                if (childAnims == null) {
551e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                    childAnims = new ArrayList<Animator>();
552e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                }
553e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                childAnims.add(anim);
554e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            }
555e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
556e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        if (parent != null && childAnims != null) {
557e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            Animator[] animsArray = new Animator[childAnims.size()];
558e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            int index = 0;
559e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            for (Animator a : childAnims) {
560e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                animsArray[index++] = a;
561e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            }
562e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            if (sequenceOrdering == TOGETHER) {
563e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                parent.playTogether(animsArray);
564e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            } else {
565e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                parent.playSequentially(animsArray);
566e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            }
567e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
568e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
569e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        return anim;
570e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
571e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    }
572e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
573fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount    private static ObjectAnimator loadObjectAnimator(Resources res, Theme theme, AttributeSet attrs,
574fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount            float pathErrorScale) throws NotFoundException {
575e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        ObjectAnimator anim = new ObjectAnimator();
576e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
577fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount        loadAnimator(res, theme, attrs, anim, pathErrorScale);
578e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
579e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        return anim;
580e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    }
581e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
582e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    /**
583e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * Creates a new animation whose parameters come from the specified context
584e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * and attributes set.
585e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     *
586e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * @param res The resources
587e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     * @param attrs The set of attributes holding the animation parameters
588cf4832f69c8786b098ce18c24319021f8cd6733aztenghui     * @param anim Null if this is a ValueAnimator, otherwise this is an
589cf4832f69c8786b098ce18c24319021f8cd6733aztenghui     *            ObjectAnimator
590e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui     */
591e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    private static ValueAnimator loadAnimator(Resources res, Theme theme,
592fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount            AttributeSet attrs, ValueAnimator anim, float pathErrorScale)
593e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            throws NotFoundException {
594e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
595cf4832f69c8786b098ce18c24319021f8cd6733aztenghui        TypedArray arrayAnimator = null;
596cf4832f69c8786b098ce18c24319021f8cd6733aztenghui        TypedArray arrayObjectAnimator = null;
597cf4832f69c8786b098ce18c24319021f8cd6733aztenghui
598e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        if (theme != null) {
599cf4832f69c8786b098ce18c24319021f8cd6733aztenghui            arrayAnimator = theme.obtainStyledAttributes(attrs, R.styleable.Animator, 0, 0);
600e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        } else {
601cf4832f69c8786b098ce18c24319021f8cd6733aztenghui            arrayAnimator = res.obtainAttributes(attrs, R.styleable.Animator);
602e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
603e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
604cf4832f69c8786b098ce18c24319021f8cd6733aztenghui        // If anim is not null, then it is an object animator.
605cf4832f69c8786b098ce18c24319021f8cd6733aztenghui        if (anim != null) {
606cf4832f69c8786b098ce18c24319021f8cd6733aztenghui            if (theme != null) {
607cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                arrayObjectAnimator = theme.obtainStyledAttributes(attrs,
608cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                        R.styleable.PropertyAnimator, 0, 0);
609cf4832f69c8786b098ce18c24319021f8cd6733aztenghui            } else {
610cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                arrayObjectAnimator = res.obtainAttributes(attrs, R.styleable.PropertyAnimator);
611cf4832f69c8786b098ce18c24319021f8cd6733aztenghui            }
612cf4832f69c8786b098ce18c24319021f8cd6733aztenghui        }
6137f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout
6147f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout        if (anim == null) {
6157f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout            anim = new ValueAnimator();
6167f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout        }
6177f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout
618fd3c4744f265c5277e6e2641a18d5ec3dff19f6bGeorge Mount        parseAnimatorFromTypeArray(anim, arrayAnimator, arrayObjectAnimator, pathErrorScale);
619d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase
620d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        final int resID =
621cf4832f69c8786b098ce18c24319021f8cd6733aztenghui                arrayAnimator.getResourceId(R.styleable.Animator_interpolator, 0);
622d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        if (resID > 0) {
623e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            anim.setInterpolator(AnimationUtils.loadInterpolator(res, theme, resID));
624d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        }
625cf4832f69c8786b098ce18c24319021f8cd6733aztenghui
626cf4832f69c8786b098ce18c24319021f8cd6733aztenghui        arrayAnimator.recycle();
6277f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout        if (arrayObjectAnimator != null) {
6287f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout            arrayObjectAnimator.recycle();
6297f9988f0f51e181f20fa22e17635d61893e5b74aCraig Stout        }
630d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase
631d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase        return anim;
632d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase    }
633d51d368f2d512ab657b8ae45780c82c0dbea94c3Chet Haase}
634