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
19d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haaseimport android.content.Context;
20e9d32ea13ee14fc0eb4e45ca627ca77729d38bfeChet Haaseimport android.util.ArrayMap;
21c43524f3869cc0d36974fce61986017093f2ecd2Chet Haaseimport android.util.Log;
22df32aa87150768795816852c6393306893467ecaChet Haaseimport android.view.View;
23faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.view.ViewGroup;
24faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.view.ViewTreeObserver;
25faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
267660d121b2ef21164ed33e6091e5dd50f5d0f939Chet Haaseimport java.lang.ref.WeakReference;
274f5072327d00822a2bfaff56df46cea2981ac90dChet Haaseimport java.util.ArrayList;
284f5072327d00822a2bfaff56df46cea2981ac90dChet Haase
29faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase/**
30faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * This class manages the set of transitions that fire when there is a
31faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * change of {@link Scene}. To use the manager, add scenes along with
32faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * transition objects with calls to {@link #setTransition(Scene, Transition)}
33faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * or {@link #setTransition(Scene, Scene, Transition)}. Setting specific
34faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * transitions for scene changes is not required; by default, a Scene change
35faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * will use {@link AutoTransition} to do something reasonable for most
36faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * situations. Specifying other transitions for particular scene changes is
37faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * only necessary if the application wants different transition behavior
38faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * in these situations.
39d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase *
40d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * <p>TransitionManagers can be declared in XML resource files inside the
41d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * <code>res/transition</code> directory. TransitionManager resources consist of
42d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * the <code>transitionManager</code>tag name, containing one or more
43d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * <code>transition</code> tags, each of which describe the relationship of
44d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * that transition to the from/to scene information in that tag.
45d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * For example, here is a resource file that declares several scene
46d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * transitions:</p>
47d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase *
48d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * {@sample development/samples/ApiDemos/res/transition/transitions_mgr.xml TransitionManager}
49d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase *
50d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * <p>For each of the <code>fromScene</code> and <code>toScene</code> attributes,
51d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * there is a reference to a standard XML layout file. This is equivalent to
52d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * creating a scene from a layout in code by calling
53d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * {@link Scene#getSceneForLayout(ViewGroup, int, Context)}. For the
54d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * <code>transition</code> attribute, there is a reference to a resource
55d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * file in the <code>res/transition</code> directory which describes that
56d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * transition.</p>
57d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase *
58d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * Information on XML resource descriptions for transitions can be found for
59d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * {@link android.R.styleable#Transition}, {@link android.R.styleable#TransitionSet},
60d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * {@link android.R.styleable#TransitionTarget}, {@link android.R.styleable#Fade},
61d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * and {@link android.R.styleable#TransitionManager}.
62faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase */
63faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haasepublic class TransitionManager {
64faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    // TODO: how to handle enter/exit?
65faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
66c43524f3869cc0d36974fce61986017093f2ecd2Chet Haase    private static String LOG_TAG = "TransitionManager";
67c43524f3869cc0d36974fce61986017093f2ecd2Chet Haase
68d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase    private static Transition sDefaultTransition = new AutoTransition();
69faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
70cfbe9be5b3b701d95fb24fa0f7c8d9be43eec776Adam Powell    private static final String[] EMPTY_STRINGS = new String[0];
71cfbe9be5b3b701d95fb24fa0f7c8d9be43eec776Adam Powell
7208735185f8105710e18ad02297461bec9268e514Chet Haase    ArrayMap<Scene, Transition> mSceneTransitions = new ArrayMap<Scene, Transition>();
7308735185f8105710e18ad02297461bec9268e514Chet Haase    ArrayMap<Scene, ArrayMap<Scene, Transition>> mScenePairTransitions =
7408735185f8105710e18ad02297461bec9268e514Chet Haase            new ArrayMap<Scene, ArrayMap<Scene, Transition>>();
757660d121b2ef21164ed33e6091e5dd50f5d0f939Chet Haase    private static ThreadLocal<WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>>
767660d121b2ef21164ed33e6091e5dd50f5d0f939Chet Haase            sRunningTransitions =
777660d121b2ef21164ed33e6091e5dd50f5d0f939Chet Haase            new ThreadLocal<WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>>();
784f5072327d00822a2bfaff56df46cea2981ac90dChet Haase    private static ArrayList<ViewGroup> sPendingTransitions = new ArrayList<ViewGroup>();
794f5072327d00822a2bfaff56df46cea2981ac90dChet Haase
80faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
814f5072327d00822a2bfaff56df46cea2981ac90dChet Haase    /**
82faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * Sets the transition to be used for any scene change for which no
83faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * other transition is explicitly set. The initial value is
84faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * an {@link AutoTransition} instance.
85faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     *
86faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @param transition The default transition to be used for scene changes.
871e9f3d868bab573072dcfa28d3b3f984de5a6756Adam Powell     *
881e9f3d868bab573072dcfa28d3b3f984de5a6756Adam Powell     * @hide pending later changes
89faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     */
90faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    public void setDefaultTransition(Transition transition) {
91d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase        sDefaultTransition = transition;
92faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
93faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
94faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    /**
95faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * Gets the current default transition. The initial value is an {@link
96faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * AutoTransition} instance.
97faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     *
98faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @return The current default transition.
99faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @see #setDefaultTransition(Transition)
1001e9f3d868bab573072dcfa28d3b3f984de5a6756Adam Powell     *
1011e9f3d868bab573072dcfa28d3b3f984de5a6756Adam Powell     * @hide pending later changes
102faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     */
103d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase    public static Transition getDefaultTransition() {
104d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase        return sDefaultTransition;
105faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
106faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
107faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    /**
108faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * Sets a specific transition to occur when the given scene is entered.
109faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     *
110faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @param scene The scene which, when applied, will cause the given
111faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * transition to run.
112faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @param transition The transition that will play when the given scene is
113faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * entered. A value of null will result in the default behavior of
1141e9f3d868bab573072dcfa28d3b3f984de5a6756Adam Powell     * using the default transition instead.
115faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     */
116faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    public void setTransition(Scene scene, Transition transition) {
117faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        mSceneTransitions.put(scene, transition);
118faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
119faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
120faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    /**
121faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * Sets a specific transition to occur when the given pair of scenes is
122faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * exited/entered.
123faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     *
124faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @param fromScene The scene being exited when the given transition will
125faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * be run
126faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @param toScene The scene being entered when the given transition will
127faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * be run
128faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @param transition The transition that will play when the given scene is
129faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * entered. A value of null will result in the default behavior of
1301e9f3d868bab573072dcfa28d3b3f984de5a6756Adam Powell     * using the default transition instead.
131faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     */
132faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    public void setTransition(Scene fromScene, Scene toScene, Transition transition) {
13308735185f8105710e18ad02297461bec9268e514Chet Haase        ArrayMap<Scene, Transition> sceneTransitionMap = mScenePairTransitions.get(toScene);
134faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        if (sceneTransitionMap == null) {
13508735185f8105710e18ad02297461bec9268e514Chet Haase            sceneTransitionMap = new ArrayMap<Scene, Transition>();
136faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            mScenePairTransitions.put(toScene, sceneTransitionMap);
137faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        }
138faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        sceneTransitionMap.put(fromScene, transition);
139faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
140faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
141faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    /**
142faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * Returns the Transition for the given scene being entered. The result
143faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * depends not only on the given scene, but also the scene which the
144faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * {@link Scene#getSceneRoot() sceneRoot} of the Scene is currently in.
145faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     *
146faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @param scene The scene being entered
147faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @return The Transition to be used for the given scene change. If no
1481e9f3d868bab573072dcfa28d3b3f984de5a6756Adam Powell     * Transition was specified for this scene change, the default transition
1491e9f3d868bab573072dcfa28d3b3f984de5a6756Adam Powell     * will be used instead.
150faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     */
151faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    private Transition getTransition(Scene scene) {
152faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        Transition transition = null;
153faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        ViewGroup sceneRoot = scene.getSceneRoot();
154faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        if (sceneRoot != null) {
155faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            // TODO: cached in Scene instead? long-term, cache in View itself
156d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase            Scene currScene = Scene.getCurrentScene(sceneRoot);
157faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            if (currScene != null) {
15808735185f8105710e18ad02297461bec9268e514Chet Haase                ArrayMap<Scene, Transition> sceneTransitionMap = mScenePairTransitions.get(scene);
159faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                if (sceneTransitionMap != null) {
160faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                    transition = sceneTransitionMap.get(currScene);
161faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                    if (transition != null) {
162faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                        return transition;
163faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                    }
164faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                }
165faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            }
166faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        }
167faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        transition = mSceneTransitions.get(scene);
168d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase        return (transition != null) ? transition : sDefaultTransition;
169faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
170faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
171faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    /**
172faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * This is where all of the work of a transition/scene-change is
173faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * orchestrated. This method captures the start values for the given
174faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * transition, exits the current Scene, enters the new scene, captures
175faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * the end values for the transition, and finally plays the
176faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * resulting values-populated transition.
177faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     *
178faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @param scene The scene being entered
179faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @param transition The transition to play for this scene change
180faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     */
1816ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase    private static void changeScene(Scene scene, Transition transition) {
182faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
183faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        final ViewGroup sceneRoot = scene.getSceneRoot();
18496e54dcfa4e2f5295b0441971f10906eeaa35328George Mount        if (!sPendingTransitions.contains(sceneRoot)) {
18596e54dcfa4e2f5295b0441971f10906eeaa35328George Mount            sPendingTransitions.add(sceneRoot);
186faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
18796e54dcfa4e2f5295b0441971f10906eeaa35328George Mount            Transition transitionClone = null;
18896e54dcfa4e2f5295b0441971f10906eeaa35328George Mount            if (transition != null) {
18996e54dcfa4e2f5295b0441971f10906eeaa35328George Mount                transitionClone = transition.clone();
19096e54dcfa4e2f5295b0441971f10906eeaa35328George Mount                transitionClone.setSceneRoot(sceneRoot);
19196e54dcfa4e2f5295b0441971f10906eeaa35328George Mount            }
1926ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase
19396e54dcfa4e2f5295b0441971f10906eeaa35328George Mount            Scene oldScene = Scene.getCurrentScene(sceneRoot);
19496e54dcfa4e2f5295b0441971f10906eeaa35328George Mount            if (oldScene != null && transitionClone != null &&
19596e54dcfa4e2f5295b0441971f10906eeaa35328George Mount                    oldScene.isCreatedFromLayoutResource()) {
19696e54dcfa4e2f5295b0441971f10906eeaa35328George Mount                transitionClone.setCanRemoveViews(true);
19796e54dcfa4e2f5295b0441971f10906eeaa35328George Mount            }
198b7a7fc9d233bad507ce893882352618b13647058Chet Haase
19996e54dcfa4e2f5295b0441971f10906eeaa35328George Mount            sceneChangeSetup(sceneRoot, transitionClone);
200faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
20196e54dcfa4e2f5295b0441971f10906eeaa35328George Mount            scene.enter();
202faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
20396e54dcfa4e2f5295b0441971f10906eeaa35328George Mount            sceneChangeRunTransition(sceneRoot, transitionClone);
20496e54dcfa4e2f5295b0441971f10906eeaa35328George Mount        }
2054f5072327d00822a2bfaff56df46cea2981ac90dChet Haase    }
2064f5072327d00822a2bfaff56df46cea2981ac90dChet Haase
207199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase    private static ArrayMap<ViewGroup, ArrayList<Transition>> getRunningTransitions() {
2087660d121b2ef21164ed33e6091e5dd50f5d0f939Chet Haase        WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>> runningTransitions =
209199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase                sRunningTransitions.get();
2107660d121b2ef21164ed33e6091e5dd50f5d0f939Chet Haase        if (runningTransitions == null || runningTransitions.get() == null) {
2117660d121b2ef21164ed33e6091e5dd50f5d0f939Chet Haase            ArrayMap<ViewGroup, ArrayList<Transition>> transitions =
2127660d121b2ef21164ed33e6091e5dd50f5d0f939Chet Haase                    new ArrayMap<ViewGroup, ArrayList<Transition>>();
2137660d121b2ef21164ed33e6091e5dd50f5d0f939Chet Haase            runningTransitions = new WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>(
2147660d121b2ef21164ed33e6091e5dd50f5d0f939Chet Haase                    transitions);
215199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase            sRunningTransitions.set(runningTransitions);
216199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase        }
2177660d121b2ef21164ed33e6091e5dd50f5d0f939Chet Haase        return runningTransitions.get();
218199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase    }
219199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase
2204f5072327d00822a2bfaff56df46cea2981ac90dChet Haase    private static void sceneChangeRunTransition(final ViewGroup sceneRoot,
2214f5072327d00822a2bfaff56df46cea2981ac90dChet Haase            final Transition transition) {
222df32aa87150768795816852c6393306893467ecaChet Haase        if (transition != null && sceneRoot != null) {
223df32aa87150768795816852c6393306893467ecaChet Haase            MultiListener listener = new MultiListener(transition, sceneRoot);
224df32aa87150768795816852c6393306893467ecaChet Haase            sceneRoot.addOnAttachStateChangeListener(listener);
225df32aa87150768795816852c6393306893467ecaChet Haase            sceneRoot.getViewTreeObserver().addOnPreDrawListener(listener);
226df32aa87150768795816852c6393306893467ecaChet Haase        }
227df32aa87150768795816852c6393306893467ecaChet Haase    }
228df32aa87150768795816852c6393306893467ecaChet Haase
229df32aa87150768795816852c6393306893467ecaChet Haase    /**
230df32aa87150768795816852c6393306893467ecaChet Haase     * This private utility class is used to listen for both OnPreDraw and
231df32aa87150768795816852c6393306893467ecaChet Haase     * OnAttachStateChange events. OnPreDraw events are the main ones we care
232df32aa87150768795816852c6393306893467ecaChet Haase     * about since that's what triggers the transition to take place.
233df32aa87150768795816852c6393306893467ecaChet Haase     * OnAttachStateChange events are also important in case the view is removed
234df32aa87150768795816852c6393306893467ecaChet Haase     * from the hierarchy before the OnPreDraw event takes place; it's used to
235df32aa87150768795816852c6393306893467ecaChet Haase     * clean up things since the OnPreDraw listener didn't get called in time.
236df32aa87150768795816852c6393306893467ecaChet Haase     */
237df32aa87150768795816852c6393306893467ecaChet Haase    private static class MultiListener implements ViewTreeObserver.OnPreDrawListener,
238df32aa87150768795816852c6393306893467ecaChet Haase            View.OnAttachStateChangeListener {
239df32aa87150768795816852c6393306893467ecaChet Haase
240df32aa87150768795816852c6393306893467ecaChet Haase        Transition mTransition;
241df32aa87150768795816852c6393306893467ecaChet Haase        ViewGroup mSceneRoot;
242df32aa87150768795816852c6393306893467ecaChet Haase
243df32aa87150768795816852c6393306893467ecaChet Haase        MultiListener(Transition transition, ViewGroup sceneRoot) {
244df32aa87150768795816852c6393306893467ecaChet Haase            mTransition = transition;
245df32aa87150768795816852c6393306893467ecaChet Haase            mSceneRoot = sceneRoot;
246df32aa87150768795816852c6393306893467ecaChet Haase        }
247df32aa87150768795816852c6393306893467ecaChet Haase
248df32aa87150768795816852c6393306893467ecaChet Haase        private void removeListeners() {
249df32aa87150768795816852c6393306893467ecaChet Haase            mSceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
250df32aa87150768795816852c6393306893467ecaChet Haase            mSceneRoot.removeOnAttachStateChangeListener(this);
251df32aa87150768795816852c6393306893467ecaChet Haase        }
252199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase
253df32aa87150768795816852c6393306893467ecaChet Haase        @Override
254df32aa87150768795816852c6393306893467ecaChet Haase        public void onViewAttachedToWindow(View v) {
255df32aa87150768795816852c6393306893467ecaChet Haase        }
256df32aa87150768795816852c6393306893467ecaChet Haase
257df32aa87150768795816852c6393306893467ecaChet Haase        @Override
258df32aa87150768795816852c6393306893467ecaChet Haase        public void onViewDetachedFromWindow(View v) {
259df32aa87150768795816852c6393306893467ecaChet Haase            removeListeners();
260df32aa87150768795816852c6393306893467ecaChet Haase
261df32aa87150768795816852c6393306893467ecaChet Haase            sPendingTransitions.remove(mSceneRoot);
262df32aa87150768795816852c6393306893467ecaChet Haase            ArrayList<Transition> runningTransitions = getRunningTransitions().get(mSceneRoot);
263df32aa87150768795816852c6393306893467ecaChet Haase            if (runningTransitions != null && runningTransitions.size() > 0) {
264df32aa87150768795816852c6393306893467ecaChet Haase                for (Transition runningTransition : runningTransitions) {
265cf68aad3164303df59b2a669d186a94533c9c743George Mount                    runningTransition.resume(mSceneRoot);
266faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                }
267df32aa87150768795816852c6393306893467ecaChet Haase            }
268df32aa87150768795816852c6393306893467ecaChet Haase            mTransition.clearValues(true);
269faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        }
270df32aa87150768795816852c6393306893467ecaChet Haase
271df32aa87150768795816852c6393306893467ecaChet Haase        @Override
272df32aa87150768795816852c6393306893467ecaChet Haase        public boolean onPreDraw() {
273df32aa87150768795816852c6393306893467ecaChet Haase            removeListeners();
274e025ed2f26858dae5f40a94a2e1ac0db808a6950Alan Viverette
275e025ed2f26858dae5f40a94a2e1ac0db808a6950Alan Viverette            // Don't start the transition if it's no longer pending.
276e025ed2f26858dae5f40a94a2e1ac0db808a6950Alan Viverette            if (!sPendingTransitions.remove(mSceneRoot)) {
277e025ed2f26858dae5f40a94a2e1ac0db808a6950Alan Viverette                return true;
278e025ed2f26858dae5f40a94a2e1ac0db808a6950Alan Viverette            }
279e025ed2f26858dae5f40a94a2e1ac0db808a6950Alan Viverette
280df32aa87150768795816852c6393306893467ecaChet Haase            // Add to running list, handle end to remove it
281df32aa87150768795816852c6393306893467ecaChet Haase            final ArrayMap<ViewGroup, ArrayList<Transition>> runningTransitions =
282df32aa87150768795816852c6393306893467ecaChet Haase                    getRunningTransitions();
283df32aa87150768795816852c6393306893467ecaChet Haase            ArrayList<Transition> currentTransitions = runningTransitions.get(mSceneRoot);
284df32aa87150768795816852c6393306893467ecaChet Haase            ArrayList<Transition> previousRunningTransitions = null;
285df32aa87150768795816852c6393306893467ecaChet Haase            if (currentTransitions == null) {
286df32aa87150768795816852c6393306893467ecaChet Haase                currentTransitions = new ArrayList<Transition>();
287df32aa87150768795816852c6393306893467ecaChet Haase                runningTransitions.put(mSceneRoot, currentTransitions);
288df32aa87150768795816852c6393306893467ecaChet Haase            } else if (currentTransitions.size() > 0) {
289df32aa87150768795816852c6393306893467ecaChet Haase                previousRunningTransitions = new ArrayList<Transition>(currentTransitions);
290df32aa87150768795816852c6393306893467ecaChet Haase            }
291df32aa87150768795816852c6393306893467ecaChet Haase            currentTransitions.add(mTransition);
292df32aa87150768795816852c6393306893467ecaChet Haase            mTransition.addListener(new Transition.TransitionListenerAdapter() {
293df32aa87150768795816852c6393306893467ecaChet Haase                @Override
294df32aa87150768795816852c6393306893467ecaChet Haase                public void onTransitionEnd(Transition transition) {
295df32aa87150768795816852c6393306893467ecaChet Haase                    ArrayList<Transition> currentTransitions =
296df32aa87150768795816852c6393306893467ecaChet Haase                            runningTransitions.get(mSceneRoot);
297df32aa87150768795816852c6393306893467ecaChet Haase                    currentTransitions.remove(transition);
298df32aa87150768795816852c6393306893467ecaChet Haase                }
299df32aa87150768795816852c6393306893467ecaChet Haase            });
300df32aa87150768795816852c6393306893467ecaChet Haase            mTransition.captureValues(mSceneRoot, false);
301df32aa87150768795816852c6393306893467ecaChet Haase            if (previousRunningTransitions != null) {
302df32aa87150768795816852c6393306893467ecaChet Haase                for (Transition runningTransition : previousRunningTransitions) {
303cf68aad3164303df59b2a669d186a94533c9c743George Mount                    runningTransition.resume(mSceneRoot);
304df32aa87150768795816852c6393306893467ecaChet Haase                }
305df32aa87150768795816852c6393306893467ecaChet Haase            }
306df32aa87150768795816852c6393306893467ecaChet Haase            mTransition.playTransition(mSceneRoot);
307df32aa87150768795816852c6393306893467ecaChet Haase
308df32aa87150768795816852c6393306893467ecaChet Haase            return true;
309df32aa87150768795816852c6393306893467ecaChet Haase        }
310df32aa87150768795816852c6393306893467ecaChet Haase    };
311faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
3124f5072327d00822a2bfaff56df46cea2981ac90dChet Haase    private static void sceneChangeSetup(ViewGroup sceneRoot, Transition transition) {
3134f5072327d00822a2bfaff56df46cea2981ac90dChet Haase
314c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase        // Capture current values
315199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase        ArrayList<Transition> runningTransitions = getRunningTransitions().get(sceneRoot);
3164f5072327d00822a2bfaff56df46cea2981ac90dChet Haase
317199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase        if (runningTransitions != null && runningTransitions.size() > 0) {
318199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase            for (Transition runningTransition : runningTransitions) {
319cf68aad3164303df59b2a669d186a94533c9c743George Mount                runningTransition.pause(sceneRoot);
320199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase            }
3214f5072327d00822a2bfaff56df46cea2981ac90dChet Haase        }
3224f5072327d00822a2bfaff56df46cea2981ac90dChet Haase
323199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase        if (transition != null) {
324199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase            transition.captureValues(sceneRoot, true);
325c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase        }
326c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase
3274f5072327d00822a2bfaff56df46cea2981ac90dChet Haase        // Notify previous scene that it is being exited
328d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase        Scene previousScene = Scene.getCurrentScene(sceneRoot);
3294f5072327d00822a2bfaff56df46cea2981ac90dChet Haase        if (previousScene != null) {
3304f5072327d00822a2bfaff56df46cea2981ac90dChet Haase            previousScene.exit();
3314f5072327d00822a2bfaff56df46cea2981ac90dChet Haase        }
3324f5072327d00822a2bfaff56df46cea2981ac90dChet Haase    }
3334f5072327d00822a2bfaff56df46cea2981ac90dChet Haase
334faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    /**
335faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * Change to the given scene, using the
336faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * appropriate transition for this particular scene change
337faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * (as specified to the TransitionManager, or the default
338faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * if no such transition exists).
339faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     *
340faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @param scene The Scene to change to
341faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     */
342faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    public void transitionTo(Scene scene) {
343faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        // Auto transition if there is no transition declared for the Scene, but there is
344faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        // a root or parent view
345faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        changeScene(scene, getTransition(scene));
346faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
347faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
348faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    /**
349d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * Convenience method to simply change to the given scene using
350faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * the default transition for TransitionManager.
351faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     *
352faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @param scene The Scene to change to
353faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     */
354faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    public static void go(Scene scene) {
355faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        changeScene(scene, sDefaultTransition);
356faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
357faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
358faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    /**
359d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * Convenience method to simply change to the given scene using
360faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * the given transition.
361faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     *
362faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * <p>Passing in <code>null</code> for the transition parameter will
363faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * result in the scene changing without any transition running, and is
364faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * equivalent to calling {@link Scene#exit()} on the scene root's
365d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * current scene, followed by {@link Scene#enter()} on the scene
366d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * specified by the <code>scene</code> parameter.</p>
367faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     *
368faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @param scene The Scene to change to
369faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @param transition The transition to use for this scene change. A
370faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * value of null causes the scene change to happen with no transition.
371faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     */
372faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    public static void go(Scene scene, Transition transition) {
373faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        changeScene(scene, transition);
374faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
375faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
376faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    /**
377d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * Convenience method to animate, using the default transition,
378d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * to a new scene defined by all changes within the given scene root between
379d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * calling this method and the next rendering frame.
380d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * Equivalent to calling {@link #beginDelayedTransition(ViewGroup, Transition)}
381d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * with a value of <code>null</code> for the <code>transition</code> parameter.
382faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     *
383faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     * @param sceneRoot The root of the View hierarchy to run the transition on.
384faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     */
385d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase    public static void beginDelayedTransition(final ViewGroup sceneRoot) {
386d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase        beginDelayedTransition(sceneRoot, null);
387faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
3884f5072327d00822a2bfaff56df46cea2981ac90dChet Haase
3894f5072327d00822a2bfaff56df46cea2981ac90dChet Haase    /**
390d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * Convenience method to animate to a new scene defined by all changes within
3914f5072327d00822a2bfaff56df46cea2981ac90dChet Haase     * the given scene root between calling this method and the next rendering frame.
3924f5072327d00822a2bfaff56df46cea2981ac90dChet Haase     * Calling this method causes TransitionManager to capture current values in the
3934f5072327d00822a2bfaff56df46cea2981ac90dChet Haase     * scene root and then post a request to run a transition on the next frame.
3944f5072327d00822a2bfaff56df46cea2981ac90dChet Haase     * At that time, the new values in the scene root will be captured and changes
3954f5072327d00822a2bfaff56df46cea2981ac90dChet Haase     * will be animated. There is no need to create a Scene; it is implied by
3964f5072327d00822a2bfaff56df46cea2981ac90dChet Haase     * changes which take place between calling this method and the next frame when
3974f5072327d00822a2bfaff56df46cea2981ac90dChet Haase     * the transition begins.
3984f5072327d00822a2bfaff56df46cea2981ac90dChet Haase     *
3994f5072327d00822a2bfaff56df46cea2981ac90dChet Haase     * <p>Calling this method several times before the next frame (for example, if
4004f5072327d00822a2bfaff56df46cea2981ac90dChet Haase     * unrelated code also wants to make dynamic changes and run a transition on
4014f5072327d00822a2bfaff56df46cea2981ac90dChet Haase     * the same scene root), only the first call will trigger capturing values
4024f5072327d00822a2bfaff56df46cea2981ac90dChet Haase     * and exiting the current scene. Subsequent calls to the method with the
4034f5072327d00822a2bfaff56df46cea2981ac90dChet Haase     * same scene root during the same frame will be ignored.</p>
4044f5072327d00822a2bfaff56df46cea2981ac90dChet Haase     *
4054f5072327d00822a2bfaff56df46cea2981ac90dChet Haase     * <p>Passing in <code>null</code> for the transition parameter will
4064f5072327d00822a2bfaff56df46cea2981ac90dChet Haase     * cause the TransitionManager to use its default transition.</p>
4074f5072327d00822a2bfaff56df46cea2981ac90dChet Haase     *
4084f5072327d00822a2bfaff56df46cea2981ac90dChet Haase     * @param sceneRoot The root of the View hierarchy to run the transition on.
4094f5072327d00822a2bfaff56df46cea2981ac90dChet Haase     * @param transition The transition to use for this change. A
4104f5072327d00822a2bfaff56df46cea2981ac90dChet Haase     * value of null causes the TransitionManager to use the default transition.
4114f5072327d00822a2bfaff56df46cea2981ac90dChet Haase     */
4124f5072327d00822a2bfaff56df46cea2981ac90dChet Haase    public static void beginDelayedTransition(final ViewGroup sceneRoot, Transition transition) {
41323c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase        if (!sPendingTransitions.contains(sceneRoot) && sceneRoot.isLaidOut()) {
41423c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase            if (Transition.DBG) {
41523c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase                Log.d(LOG_TAG, "beginDelayedTransition: root, transition = " +
41623c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase                        sceneRoot + ", " + transition);
41723c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase            }
41823c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase            sPendingTransitions.add(sceneRoot);
41923c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase            if (transition == null) {
42023c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase                transition = sDefaultTransition;
42123c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase            }
42223c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase            final Transition transitionClone = transition.clone();
42323c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase            sceneChangeSetup(sceneRoot, transitionClone);
42423c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase            Scene.setCurrentScene(sceneRoot, null);
42523c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase            sceneChangeRunTransition(sceneRoot, transitionClone);
42623c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase        }
4274f5072327d00822a2bfaff56df46cea2981ac90dChet Haase    }
428e025ed2f26858dae5f40a94a2e1ac0db808a6950Alan Viverette
429e025ed2f26858dae5f40a94a2e1ac0db808a6950Alan Viverette    /**
430e025ed2f26858dae5f40a94a2e1ac0db808a6950Alan Viverette     * Ends all pending and ongoing transitions on the specified scene root.
431e025ed2f26858dae5f40a94a2e1ac0db808a6950Alan Viverette     *
432e025ed2f26858dae5f40a94a2e1ac0db808a6950Alan Viverette     * @param sceneRoot The root of the View hierarchy to end transitions on.
433e025ed2f26858dae5f40a94a2e1ac0db808a6950Alan Viverette     */
434e025ed2f26858dae5f40a94a2e1ac0db808a6950Alan Viverette    public static void endTransitions(final ViewGroup sceneRoot) {
435e025ed2f26858dae5f40a94a2e1ac0db808a6950Alan Viverette        sPendingTransitions.remove(sceneRoot);
436e025ed2f26858dae5f40a94a2e1ac0db808a6950Alan Viverette
437e025ed2f26858dae5f40a94a2e1ac0db808a6950Alan Viverette        final ArrayList<Transition> runningTransitions = getRunningTransitions().get(sceneRoot);
438800320933e849cc370a96d032c65fbddcc4fac9dGeorge Mount        if (runningTransitions != null && !runningTransitions.isEmpty()) {
439800320933e849cc370a96d032c65fbddcc4fac9dGeorge Mount            // Make a copy in case this is called by an onTransitionEnd listener
440800320933e849cc370a96d032c65fbddcc4fac9dGeorge Mount            ArrayList<Transition> copy = new ArrayList(runningTransitions);
441800320933e849cc370a96d032c65fbddcc4fac9dGeorge Mount            for (int i = copy.size() - 1; i >= 0; i--) {
442800320933e849cc370a96d032c65fbddcc4fac9dGeorge Mount                final Transition transition = copy.get(i);
443413739e8c62a7cd83ec519203a2628504b1b0d16George Mount                transition.forceToEnd(sceneRoot);
444e025ed2f26858dae5f40a94a2e1ac0db808a6950Alan Viverette            }
445e025ed2f26858dae5f40a94a2e1ac0db808a6950Alan Viverette        }
446e025ed2f26858dae5f40a94a2e1ac0db808a6950Alan Viverette
447e025ed2f26858dae5f40a94a2e1ac0db808a6950Alan Viverette    }
448faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase}
449