1faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase/*
2faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * Copyright (C) 2013 The Android Open Source Project
3faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase *
4faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * Licensed under the Apache License, Version 2.0 (the "License");
5faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * you may not use this file except in compliance with the License.
6faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * You may obtain a copy of the License at
7faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase *
8faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase *      http://www.apache.org/licenses/LICENSE-2.0
9faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase *
10faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * Unless required by applicable law or agreed to in writing, software
11faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * distributed under the License is distributed on an "AS IS" BASIS,
12faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * See the License for the specific language governing permissions and
14faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * limitations under the License.
15faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase */
166ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase
17d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haasepackage android.transition;
18faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
19faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.content.Context;
20faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.content.res.Resources;
21faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.content.res.TypedArray;
22faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.content.res.XmlResourceParser;
23faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.util.AttributeSet;
24faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.util.Xml;
25faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.view.InflateException;
26faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.view.ViewGroup;
27faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.view.animation.AnimationUtils;
28faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport org.xmlpull.v1.XmlPullParser;
29faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport org.xmlpull.v1.XmlPullParserException;
30faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
31faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport java.io.IOException;
32faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport java.util.ArrayList;
33faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
34faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase/**
35faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * This class inflates scenes and transitions from resource files.
36d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase *
37d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * Information on XML resource descriptions for transitions can be found for
38d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * {@link android.R.styleable#Transition}, {@link android.R.styleable#TransitionSet},
39d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * {@link android.R.styleable#TransitionTarget}, {@link android.R.styleable#Fade},
40d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * and {@link android.R.styleable#TransitionManager}.
41faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase */
42faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haasepublic class TransitionInflater {
43faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
44faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    private Context mContext;
45faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
46faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    private TransitionInflater(Context context) {
47faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        mContext = context;
48faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
49faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
50faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    /**
51faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * Obtains the TransitionInflater from the given context.
52faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     */
53faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    public static TransitionInflater from(Context context) {
5458ad12208afcf9fdce735dead8449c4db375344dChet Haase        return new TransitionInflater(context);
55faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
56faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
57faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    /**
58faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * Loads a {@link Transition} object from a resource
59faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     *
60faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @param resource The resource id of the transition to load
61faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @return The loaded Transition object
62faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @throws android.content.res.Resources.NotFoundException when the
63faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * transition cannot be loaded
64faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     */
65faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    public Transition inflateTransition(int resource) {
66faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        XmlResourceParser parser =  mContext.getResources().getXml(resource);
67faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        try {
68faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            return createTransitionFromXml(parser, Xml.asAttributeSet(parser), null);
69faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        } catch (XmlPullParserException e) {
70faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            InflateException ex = new InflateException(e.getMessage());
71faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            ex.initCause(e);
72faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            throw ex;
73faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        } catch (IOException e) {
74faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            InflateException ex = new InflateException(
75faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                    parser.getPositionDescription()
76faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                            + ": " + e.getMessage());
77faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            ex.initCause(e);
78faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            throw ex;
79faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        } finally {
80faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            parser.close();
81faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        }
82faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
83faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
84faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    /**
85faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * Loads a {@link TransitionManager} object from a resource
86faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     *
87faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     *
88faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     *
89faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @param resource The resource id of the transition manager to load
90faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @return The loaded TransitionManager object
91faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @throws android.content.res.Resources.NotFoundException when the
92faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * transition manager cannot be loaded
93faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     */
94faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    public TransitionManager inflateTransitionManager(int resource, ViewGroup sceneRoot) {
95faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        XmlResourceParser parser =  mContext.getResources().getXml(resource);
96faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        try {
97faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            return createTransitionManagerFromXml(parser, Xml.asAttributeSet(parser), sceneRoot);
98faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        } catch (XmlPullParserException e) {
99faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            InflateException ex = new InflateException(e.getMessage());
100faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            ex.initCause(e);
101faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            throw ex;
102faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        } catch (IOException e) {
103faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            InflateException ex = new InflateException(
104faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                    parser.getPositionDescription()
105faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                            + ": " + e.getMessage());
106faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            ex.initCause(e);
107faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            throw ex;
108faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        } finally {
109faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            parser.close();
110faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        }
111faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
112faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
113faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    //
114faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    // Transition loading
115faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    //
116faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
117faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    private Transition createTransitionFromXml(XmlPullParser parser,
118d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase            AttributeSet attrs, TransitionSet transitionSet)
119faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            throws XmlPullParserException, IOException {
120faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
121faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        Transition transition = null;
122faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
123faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        // Make sure we are on a start tag.
124faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        int type;
125faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        int depth = parser.getDepth();
126faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
127faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
128faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                && type != XmlPullParser.END_DOCUMENT) {
129faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
130faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            boolean newTransition = false;
131faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
132faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            if (type != XmlPullParser.START_TAG) {
133faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                continue;
134faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            }
135faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
136faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            String  name = parser.getName();
137faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            if ("fade".equals(name)) {
138d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase                TypedArray a = mContext.obtainStyledAttributes(attrs,
139d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase                        com.android.internal.R.styleable.Fade);
140d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase                int fadingMode = a.getInt(com.android.internal.R.styleable.Fade_fadingMode,
141d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase                        Fade.IN | Fade.OUT);
142d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase                transition = new Fade(fadingMode);
143faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                newTransition = true;
144d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase            } else if ("changeBounds".equals(name)) {
145d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase                transition = new ChangeBounds();
146faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                newTransition = true;
147faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            } else if ("slide".equals(name)) {
148faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                transition = new Slide();
149faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                newTransition = true;
150faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            } else if ("autoTransition".equals(name)) {
151faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                transition = new AutoTransition();
152faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                newTransition = true;
153faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            } else if ("recolor".equals(name)) {
154faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                transition = new Recolor();
155faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                newTransition = true;
156aafc91c05acfb2d5a95f46f27e1deb2dfaa15c32Chet Haase            } else if ("transitionSet".equals(name)) {
157d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase                transition = new TransitionSet();
158d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase                TypedArray a = mContext.obtainStyledAttributes(attrs,
159d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase                        com.android.internal.R.styleable.TransitionSet);
160d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase                int ordering = a.getInt(
161d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase                        com.android.internal.R.styleable.TransitionSet_transitionOrdering,
162d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase                        TransitionSet.ORDERING_TOGETHER);
163d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase                ((TransitionSet) transition).setOrdering(ordering);
164d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase                createTransitionFromXml(parser, attrs, ((TransitionSet) transition));
165d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase                a.recycle();
166faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                newTransition = true;
167faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            } else if ("targets".equals(name)) {
168faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                if (parser.getDepth() - 1 > depth && transition != null) {
169faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                    // We're inside the child tag - add targets to the child
170d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase                    getTargetIds(parser, attrs, transition);
171d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase                } else if (parser.getDepth() - 1 == depth && transitionSet != null) {
172d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase                    // add targets to the set
173d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase                    getTargetIds(parser, attrs, transitionSet);
174faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                }
175faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            }
176faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            if (transition != null || "targets".equals(name)) {
177faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                if (newTransition) {
178faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                    loadTransition(transition, attrs);
179d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase                    if (transitionSet != null) {
180d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase                        transitionSet.addTransition(transition);
181faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                    }
182faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                }
183faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            } else {
184faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                throw new RuntimeException("Unknown scene name: " + parser.getName());
185faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            }
186faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        }
187faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
188faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        return transition;
189faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
190faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
191d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase    private void getTargetIds(XmlPullParser parser,
192faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            AttributeSet attrs, Transition transition) throws XmlPullParserException, IOException {
193faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
194faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        // Make sure we are on a start tag.
195faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        int type;
196faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        int depth = parser.getDepth();
197faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
198faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        ArrayList<Integer> targetIds = new ArrayList<Integer>();
199faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
200faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                && type != XmlPullParser.END_DOCUMENT) {
201faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
202faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            if (type != XmlPullParser.START_TAG) {
203faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                continue;
204faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            }
205faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
206faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            String  name = parser.getName();
207faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            if (name.equals("target")) {
208faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                TypedArray a = mContext.obtainStyledAttributes(attrs,
209d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase                        com.android.internal.R.styleable.TransitionTarget);
210d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase                int id = a.getResourceId(
211d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase                        com.android.internal.R.styleable.TransitionTarget_targetId, -1);
212faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                if (id >= 0) {
213faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                    targetIds.add(id);
214faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                }
215faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            } else {
216faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                throw new RuntimeException("Unknown scene name: " + parser.getName());
217faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            }
218faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        }
219faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        int numTargets = targetIds.size();
220faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        if (numTargets > 0) {
221d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase            for (int i = 0; i < numTargets; ++i) {
222ff58f92a0a77ad849ba714b5adac96790eca0048Chet Haase                transition.addTarget(targetIds.get(i));
223faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            }
224faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        }
225faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
226faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
227faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    private Transition loadTransition(Transition transition, AttributeSet attrs)
228faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            throws Resources.NotFoundException {
229faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
230faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        TypedArray a =
231faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                mContext.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Transition);
232faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        long duration = a.getInt(com.android.internal.R.styleable.Transition_duration, -1);
233faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        if (duration >= 0) {
234faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            transition.setDuration(duration);
235faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        }
236d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase        long startDelay = a.getInt(com.android.internal.R.styleable.Transition_startDelay, -1);
237d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase        if (startDelay > 0) {
238d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase            transition.setStartDelay(startDelay);
239faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        }
240faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        final int resID =
241faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                a.getResourceId(com.android.internal.R.styleable.Animator_interpolator, 0);
242faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        if (resID > 0) {
243faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            transition.setInterpolator(AnimationUtils.loadInterpolator(mContext, resID));
244faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        }
245faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        a.recycle();
246faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        return transition;
247faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
248faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
249faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    //
250faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    // TransitionManager loading
251faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    //
252faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
253faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    private TransitionManager createTransitionManagerFromXml(XmlPullParser parser,
254faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            AttributeSet attrs, ViewGroup sceneRoot) throws XmlPullParserException, IOException {
255faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
256faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        // Make sure we are on a start tag.
257faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        int type;
258faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        int depth = parser.getDepth();
259faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        TransitionManager transitionManager = null;
260faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
261faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
262faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                && type != XmlPullParser.END_DOCUMENT) {
263faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
264faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            if (type != XmlPullParser.START_TAG) {
265faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                continue;
266faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            }
267faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
268faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            String  name = parser.getName();
269faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            if (name.equals("transitionManager")) {
270faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                transitionManager = new TransitionManager();
271faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            } else if (name.equals("transition") && (transitionManager != null)) {
272faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                loadTransition(attrs, sceneRoot, transitionManager);
273faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            } else {
274faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                throw new RuntimeException("Unknown scene name: " + parser.getName());
275faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            }
276faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        }
277faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        return transitionManager;
278faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
279faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
280faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    private void loadTransition(AttributeSet attrs, ViewGroup sceneRoot,
281d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase            TransitionManager transitionManager) throws Resources.NotFoundException {
282faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
283faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        TypedArray a = mContext.obtainStyledAttributes(attrs,
284faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                com.android.internal.R.styleable.TransitionManager);
285d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase        int transitionId = a.getResourceId(
286faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                com.android.internal.R.styleable.TransitionManager_transition, -1);
287faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        Scene fromScene = null, toScene = null;
288d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase        int fromId = a.getResourceId(
289faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                com.android.internal.R.styleable.TransitionManager_fromScene, -1);
290d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase        if (fromId >= 0) fromScene = Scene.getSceneForLayout(sceneRoot, fromId, mContext);
291d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase        int toId = a.getResourceId(
292faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                com.android.internal.R.styleable.TransitionManager_toScene, -1);
293d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase        if (toId >= 0) toScene = Scene.getSceneForLayout(sceneRoot, toId, mContext);
294faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        if (transitionId >= 0) {
295faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            Transition transition = inflateTransition(transitionId);
296faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            if (transition != null) {
297faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                if (fromScene != null) {
298faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                    if (toScene == null){
299faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                        throw new RuntimeException("No matching toScene for given fromScene " +
300faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                                "for transition ID " + transitionId);
301faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                    } else {
302faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                        transitionManager.setTransition(fromScene, toScene, transition);
303faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                    }
304faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                } else if (toId >= 0) {
305faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                    transitionManager.setTransition(toScene, transition);
306faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                }
307faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            }
308faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        }
309faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        a.recycle();
310faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
311faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase}
312