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
19bc2dd79af9acc538b131506a1ea54fcc7000b164Tor Norbyeimport android.annotation.TransitionRes;
20ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mountimport com.android.internal.R;
21ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount
22ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mountimport org.xmlpull.v1.XmlPullParser;
23ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mountimport org.xmlpull.v1.XmlPullParserException;
24ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount
25faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.content.Context;
26faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.content.res.Resources;
27faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.content.res.TypedArray;
28faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.content.res.XmlResourceParser;
29ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mountimport android.util.ArrayMap;
30faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.util.AttributeSet;
31faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.util.Xml;
32faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.view.InflateException;
33faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.view.ViewGroup;
34faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
35faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport java.io.IOException;
36ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mountimport java.lang.reflect.Constructor;
37ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mountimport java.lang.reflect.InvocationTargetException;
38faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
39faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase/**
40faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * This class inflates scenes and transitions from resource files.
41d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase *
42d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * Information on XML resource descriptions for transitions can be found for
43d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * {@link android.R.styleable#Transition}, {@link android.R.styleable#TransitionSet},
44d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * {@link android.R.styleable#TransitionTarget}, {@link android.R.styleable#Fade},
45d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * and {@link android.R.styleable#TransitionManager}.
46faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase */
47faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haasepublic class TransitionInflater {
48ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount
49ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount    private static final Class<?>[] sConstructorSignature = new Class[] {
50ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount            Context.class, AttributeSet.class};
51ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount    private final static ArrayMap<String, Constructor> sConstructors =
52ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount            new ArrayMap<String, Constructor>();
53faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
54faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    private Context mContext;
55faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
56faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    private TransitionInflater(Context context) {
57faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        mContext = context;
58faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
59faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
60faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    /**
61faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * Obtains the TransitionInflater from the given context.
62faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     */
63faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    public static TransitionInflater from(Context context) {
6458ad12208afcf9fdce735dead8449c4db375344dChet Haase        return new TransitionInflater(context);
65faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
66faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
67faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    /**
68faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * Loads a {@link Transition} object from a resource
69faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     *
70faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @param resource The resource id of the transition to load
71faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @return The loaded Transition object
72faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @throws android.content.res.Resources.NotFoundException when the
73faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * transition cannot be loaded
74faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     */
75bc2dd79af9acc538b131506a1ea54fcc7000b164Tor Norbye    public Transition inflateTransition(@TransitionRes int resource) {
76bc2dd79af9acc538b131506a1ea54fcc7000b164Tor Norbye        //noinspection ResourceType
77faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        XmlResourceParser parser =  mContext.getResources().getXml(resource);
78faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        try {
79faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            return createTransitionFromXml(parser, Xml.asAttributeSet(parser), null);
80faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        } catch (XmlPullParserException e) {
81faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            InflateException ex = new InflateException(e.getMessage());
82faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            ex.initCause(e);
83faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            throw ex;
84faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        } catch (IOException e) {
85faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            InflateException ex = new InflateException(
86faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                    parser.getPositionDescription()
87faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                            + ": " + e.getMessage());
88faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            ex.initCause(e);
89faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            throw ex;
90faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        } finally {
91faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            parser.close();
92faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        }
93faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
94faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
95faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    /**
96faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * Loads a {@link TransitionManager} object from a resource
97faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     *
98faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @param resource The resource id of the transition manager to load
99faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @return The loaded TransitionManager object
100faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @throws android.content.res.Resources.NotFoundException when the
101faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * transition manager cannot be loaded
102faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     */
103bc2dd79af9acc538b131506a1ea54fcc7000b164Tor Norbye    public TransitionManager inflateTransitionManager(@TransitionRes int resource,
104bc2dd79af9acc538b131506a1ea54fcc7000b164Tor Norbye            ViewGroup sceneRoot) {
105bc2dd79af9acc538b131506a1ea54fcc7000b164Tor Norbye        //noinspection ResourceType
106faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        XmlResourceParser parser =  mContext.getResources().getXml(resource);
107faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        try {
108faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            return createTransitionManagerFromXml(parser, Xml.asAttributeSet(parser), sceneRoot);
109faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        } catch (XmlPullParserException e) {
110faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            InflateException ex = new InflateException(e.getMessage());
111faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            ex.initCause(e);
112faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            throw ex;
113faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        } catch (IOException e) {
114faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            InflateException ex = new InflateException(
115faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                    parser.getPositionDescription()
116faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                            + ": " + e.getMessage());
117faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            ex.initCause(e);
118faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            throw ex;
119faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        } finally {
120faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            parser.close();
121faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        }
122faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
123faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
124faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    //
125faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    // Transition loading
126faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    //
127faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    private Transition createTransitionFromXml(XmlPullParser parser,
128ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount            AttributeSet attrs, Transition parent)
129faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            throws XmlPullParserException, IOException {
130faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
131faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        Transition transition = null;
132faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
133faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        // Make sure we are on a start tag.
134faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        int type;
135faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        int depth = parser.getDepth();
136faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
137ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount        TransitionSet transitionSet = (parent instanceof TransitionSet)
138ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                ? (TransitionSet) parent : null;
139ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount
140faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
141faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                && type != XmlPullParser.END_DOCUMENT) {
142faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
143faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            if (type != XmlPullParser.START_TAG) {
144faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                continue;
145faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            }
146faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
147faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            String  name = parser.getName();
148faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            if ("fade".equals(name)) {
149ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                transition = new Fade(mContext, attrs);
150d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase            } else if ("changeBounds".equals(name)) {
151ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                transition = new ChangeBounds(mContext, attrs);
152faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            } else if ("slide".equals(name)) {
153ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                transition = new Slide(mContext, attrs);
154d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            } else if ("explode".equals(name)) {
155ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                transition = new Explode(mContext, attrs);
156990205eada00ad3e575761d19607bb03e12f9aa3George Mount            } else if ("changeImageTransform".equals(name)) {
157ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                transition = new ChangeImageTransform(mContext, attrs);
158608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount            } else if ("changeTransform".equals(name)) {
159ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                transition = new ChangeTransform(mContext, attrs);
160608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount            } else if ("changeClipBounds".equals(name)) {
161ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                transition = new ChangeClipBounds(mContext, attrs);
162faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            } else if ("autoTransition".equals(name)) {
163ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                transition = new AutoTransition(mContext, attrs);
164faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            } else if ("recolor".equals(name)) {
165ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                transition = new Recolor(mContext, attrs);
1662dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos            } else if ("changeScroll".equals(name)) {
1672dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos                transition = new ChangeScroll(mContext, attrs);
168aafc91c05acfb2d5a95f46f27e1deb2dfaa15c32Chet Haase            } else if ("transitionSet".equals(name)) {
169ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                transition = new TransitionSet(mContext, attrs);
17044d663849481576fb649aeb6234086406ced75f1George Mount            } else if ("transition".equals(name)) {
171ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                transition = (Transition) createCustom(attrs, Transition.class, "transition");
172faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            } else if ("targets".equals(name)) {
173ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                getTargetIds(parser, attrs, parent);
174ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount            } else if ("arcMotion".equals(name)) {
175ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                parent.setPathMotion(new ArcMotion(mContext, attrs));
176ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount            } else if ("pathMotion".equals(name)) {
177ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                parent.setPathMotion((PathMotion)createCustom(attrs, PathMotion.class, "pathMotion"));
178f9557619a7643c971e64e5b35583476202e77b7bGeorge Mount            } else if ("patternPathMotion".equals(name)) {
179f9557619a7643c971e64e5b35583476202e77b7bGeorge Mount                parent.setPathMotion(new PatternPathMotion(mContext, attrs));
180faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            } else {
181faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                throw new RuntimeException("Unknown scene name: " + parser.getName());
182faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            }
183ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount            if (transition != null) {
184ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                if (!parser.isEmptyElementTag()) {
185ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                    createTransitionFromXml(parser, attrs, transition);
186ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                }
187ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                if (transitionSet != null) {
188ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                    transitionSet.addTransition(transition);
189ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                    transition = null;
190ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                } else if (parent != null) {
191ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                    throw new InflateException("Could not add transition to another transition.");
192ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                }
193ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount            }
194faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        }
195faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
196faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        return transition;
197faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
198faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
199ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount    private Object createCustom(AttributeSet attrs, Class expectedType, String tag) {
20044d663849481576fb649aeb6234086406ced75f1George Mount        String className = attrs.getAttributeValue(null, "class");
20144d663849481576fb649aeb6234086406ced75f1George Mount
20244d663849481576fb649aeb6234086406ced75f1George Mount        if (className == null) {
203ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount            throw new InflateException(tag + " tag must have a 'class' attribute");
20444d663849481576fb649aeb6234086406ced75f1George Mount        }
20544d663849481576fb649aeb6234086406ced75f1George Mount
20644d663849481576fb649aeb6234086406ced75f1George Mount        try {
207ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount            synchronized (sConstructors) {
208ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                Constructor constructor = sConstructors.get(className);
209ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                if (constructor == null) {
210ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                    Class c = mContext.getClassLoader().loadClass(className)
211ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                            .asSubclass(expectedType);
212ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                    if (c != null) {
213ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                        constructor = c.getConstructor(sConstructorSignature);
214904de2ec9360de2ee54b91aaf9e141d9d8ab1de1Alan Viverette                        constructor.setAccessible(true);
215ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                        sConstructors.put(className, constructor);
216ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                    }
217ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                }
218ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                return constructor.newInstance(mContext, attrs);
21944d663849481576fb649aeb6234086406ced75f1George Mount            }
22044d663849481576fb649aeb6234086406ced75f1George Mount        } catch (InstantiationException e) {
221ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount            throw new InflateException("Could not instantiate " + expectedType + " class " +
222ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                    className, e);
22344d663849481576fb649aeb6234086406ced75f1George Mount        } catch (ClassNotFoundException e) {
224ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount            throw new InflateException("Could not instantiate " + expectedType + " class " +
225ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                    className, e);
226ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount        } catch (InvocationTargetException e) {
227ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount            throw new InflateException("Could not instantiate " + expectedType + " class " +
228ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                    className, e);
229ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount        } catch (NoSuchMethodException e) {
230ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount            throw new InflateException("Could not instantiate " + expectedType + " class " +
231ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                    className, e);
232ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount        } catch (IllegalAccessException e) {
233ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount            throw new InflateException("Could not instantiate " + expectedType + " class " +
234ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                    className, e);
23544d663849481576fb649aeb6234086406ced75f1George Mount        }
23644d663849481576fb649aeb6234086406ced75f1George Mount    }
23744d663849481576fb649aeb6234086406ced75f1George Mount
238d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase    private void getTargetIds(XmlPullParser parser,
239faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            AttributeSet attrs, Transition transition) throws XmlPullParserException, IOException {
240faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
241faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        // Make sure we are on a start tag.
242faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        int type;
243faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        int depth = parser.getDepth();
244faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
245faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
246faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                && type != XmlPullParser.END_DOCUMENT) {
247faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
248faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            if (type != XmlPullParser.START_TAG) {
249faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                continue;
250faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            }
251faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
252faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            String  name = parser.getName();
253faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            if (name.equals("target")) {
254ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.TransitionTarget);
255ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                int id = a.getResourceId(R.styleable.TransitionTarget_targetId, 0);
2560a2ae002e60f7ea9b6bea282086b5eb0ae3c6e51George Mount                String transitionName;
257ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                if (id != 0) {
258f976c3d42bc2f14333bae5ed26d96c45d207a443George Mount                    transition.addTarget(id);
259ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                } else if ((id = a.getResourceId(R.styleable.TransitionTarget_excludeId, 0)) != 0) {
260a98fb7ab6a17d27395cf2c8e86060af49b861be6George Mount                    transition.excludeTarget(id, true);
261ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                } else if ((transitionName = a.getString(R.styleable.TransitionTarget_targetName))
26230da61d477bcb6cc7718f9516c444359352fe148George Mount                        != null) {
2630a2ae002e60f7ea9b6bea282086b5eb0ae3c6e51George Mount                    transition.addTarget(transitionName);
264ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                } else if ((transitionName = a.getString(R.styleable.TransitionTarget_excludeName))
26530da61d477bcb6cc7718f9516c444359352fe148George Mount                        != null) {
2660a2ae002e60f7ea9b6bea282086b5eb0ae3c6e51George Mount                    transition.excludeTarget(transitionName, true);
267f976c3d42bc2f14333bae5ed26d96c45d207a443George Mount                } else {
268ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                    String className = a.getString(R.styleable.TransitionTarget_excludeClass);
269a98fb7ab6a17d27395cf2c8e86060af49b861be6George Mount                    try {
270f976c3d42bc2f14333bae5ed26d96c45d207a443George Mount                        if (className != null) {
271a98fb7ab6a17d27395cf2c8e86060af49b861be6George Mount                            Class clazz = Class.forName(className);
272a98fb7ab6a17d27395cf2c8e86060af49b861be6George Mount                            transition.excludeTarget(clazz, true);
273ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                        } else if ((className =
274ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount                                a.getString(R.styleable.TransitionTarget_targetClass)) != null) {
275a98fb7ab6a17d27395cf2c8e86060af49b861be6George Mount                            Class clazz = Class.forName(className);
276a98fb7ab6a17d27395cf2c8e86060af49b861be6George Mount                            transition.addTarget(clazz);
277f976c3d42bc2f14333bae5ed26d96c45d207a443George Mount                        }
278a98fb7ab6a17d27395cf2c8e86060af49b861be6George Mount                    } catch (ClassNotFoundException e) {
279a98fb7ab6a17d27395cf2c8e86060af49b861be6George Mount                        throw new RuntimeException("Could not create " + className, e);
280f976c3d42bc2f14333bae5ed26d96c45d207a443George Mount                    }
281faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                }
282faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            } else {
283faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                throw new RuntimeException("Unknown scene name: " + parser.getName());
284faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            }
285faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        }
286faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
287faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
288faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    //
289faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    // TransitionManager loading
290faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    //
291faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
292faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    private TransitionManager createTransitionManagerFromXml(XmlPullParser parser,
293faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            AttributeSet attrs, ViewGroup sceneRoot) throws XmlPullParserException, IOException {
294faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
295faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        // Make sure we are on a start tag.
296faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        int type;
297faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        int depth = parser.getDepth();
298faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        TransitionManager transitionManager = null;
299faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
300faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
301faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                && type != XmlPullParser.END_DOCUMENT) {
302faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
303faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            if (type != XmlPullParser.START_TAG) {
304faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                continue;
305faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            }
306faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
307faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            String  name = parser.getName();
308faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            if (name.equals("transitionManager")) {
309faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                transitionManager = new TransitionManager();
310faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            } else if (name.equals("transition") && (transitionManager != null)) {
311faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                loadTransition(attrs, sceneRoot, transitionManager);
312faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            } else {
313faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                throw new RuntimeException("Unknown scene name: " + parser.getName());
314faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            }
315faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        }
316faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        return transitionManager;
317faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
318faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
319faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    private void loadTransition(AttributeSet attrs, ViewGroup sceneRoot,
320d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase            TransitionManager transitionManager) throws Resources.NotFoundException {
321faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
322ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount        TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.TransitionManager);
323ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount        int transitionId = a.getResourceId(R.styleable.TransitionManager_transition, -1);
324ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount        int fromId = a.getResourceId(R.styleable.TransitionManager_fromScene, -1);
325e180337ee99b9155fe441ea55451f4d2167b5d9aGeorge Mount        Scene fromScene = (fromId < 0) ? null: Scene.getSceneForLayout(sceneRoot, fromId, mContext);
326ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount        int toId = a.getResourceId(R.styleable.TransitionManager_toScene, -1);
327e180337ee99b9155fe441ea55451f4d2167b5d9aGeorge Mount        Scene toScene = (toId < 0) ? null : Scene.getSceneForLayout(sceneRoot, toId, mContext);
328e180337ee99b9155fe441ea55451f4d2167b5d9aGeorge Mount
329faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        if (transitionId >= 0) {
330faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            Transition transition = inflateTransition(transitionId);
331faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            if (transition != null) {
33231a217290cf376d0573fc36e21c8940987485019George Mount                if (toScene == null) {
33331a217290cf376d0573fc36e21c8940987485019George Mount                    throw new RuntimeException("No toScene for transition ID " + transitionId);
33431a217290cf376d0573fc36e21c8940987485019George Mount                }
335e180337ee99b9155fe441ea55451f4d2167b5d9aGeorge Mount                if (fromScene == null) {
33631a217290cf376d0573fc36e21c8940987485019George Mount                    transitionManager.setTransition(toScene, transition);
337e180337ee99b9155fe441ea55451f4d2167b5d9aGeorge Mount                } else {
338e180337ee99b9155fe441ea55451f4d2167b5d9aGeorge Mount                    transitionManager.setTransition(fromScene, toScene, transition);
339cfbe9be5b3b701d95fb24fa0f7c8d9be43eec776Adam Powell                }
340faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            }
341faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        }
342faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        a.recycle();
343faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
344faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase}
345