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(); 184faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase 1855a7cf3eeeb208c2dac52541cb09b519b4342a5ffChet Haase Transition transitionClone = null; 1865a7cf3eeeb208c2dac52541cb09b519b4342a5ffChet Haase if (transition != null) { 1875a7cf3eeeb208c2dac52541cb09b519b4342a5ffChet Haase transitionClone = transition.clone(); 1885a7cf3eeeb208c2dac52541cb09b519b4342a5ffChet Haase transitionClone.setSceneRoot(sceneRoot); 1895a7cf3eeeb208c2dac52541cb09b519b4342a5ffChet Haase } 1906ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase 191b7a7fc9d233bad507ce893882352618b13647058Chet Haase Scene oldScene = Scene.getCurrentScene(sceneRoot); 1925a7cf3eeeb208c2dac52541cb09b519b4342a5ffChet Haase if (oldScene != null && transitionClone != null && 1935a7cf3eeeb208c2dac52541cb09b519b4342a5ffChet Haase oldScene.isCreatedFromLayoutResource()) { 194b7a7fc9d233bad507ce893882352618b13647058Chet Haase transitionClone.setCanRemoveViews(true); 195b7a7fc9d233bad507ce893882352618b13647058Chet Haase } 196b7a7fc9d233bad507ce893882352618b13647058Chet Haase 1976ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase sceneChangeSetup(sceneRoot, transitionClone); 198faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase 199faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase scene.enter(); 200faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase 2016ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase sceneChangeRunTransition(sceneRoot, transitionClone); 2024f5072327d00822a2bfaff56df46cea2981ac90dChet Haase } 2034f5072327d00822a2bfaff56df46cea2981ac90dChet Haase 204199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase private static ArrayMap<ViewGroup, ArrayList<Transition>> getRunningTransitions() { 2057660d121b2ef21164ed33e6091e5dd50f5d0f939Chet Haase WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>> runningTransitions = 206199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase sRunningTransitions.get(); 2077660d121b2ef21164ed33e6091e5dd50f5d0f939Chet Haase if (runningTransitions == null || runningTransitions.get() == null) { 2087660d121b2ef21164ed33e6091e5dd50f5d0f939Chet Haase ArrayMap<ViewGroup, ArrayList<Transition>> transitions = 2097660d121b2ef21164ed33e6091e5dd50f5d0f939Chet Haase new ArrayMap<ViewGroup, ArrayList<Transition>>(); 2107660d121b2ef21164ed33e6091e5dd50f5d0f939Chet Haase runningTransitions = new WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>( 2117660d121b2ef21164ed33e6091e5dd50f5d0f939Chet Haase transitions); 212199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase sRunningTransitions.set(runningTransitions); 213199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase } 2147660d121b2ef21164ed33e6091e5dd50f5d0f939Chet Haase return runningTransitions.get(); 215199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase } 216199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase 2174f5072327d00822a2bfaff56df46cea2981ac90dChet Haase private static void sceneChangeRunTransition(final ViewGroup sceneRoot, 2184f5072327d00822a2bfaff56df46cea2981ac90dChet Haase final Transition transition) { 219df32aa87150768795816852c6393306893467ecaChet Haase if (transition != null && sceneRoot != null) { 220df32aa87150768795816852c6393306893467ecaChet Haase MultiListener listener = new MultiListener(transition, sceneRoot); 221df32aa87150768795816852c6393306893467ecaChet Haase sceneRoot.addOnAttachStateChangeListener(listener); 222df32aa87150768795816852c6393306893467ecaChet Haase sceneRoot.getViewTreeObserver().addOnPreDrawListener(listener); 223df32aa87150768795816852c6393306893467ecaChet Haase } 224df32aa87150768795816852c6393306893467ecaChet Haase } 225df32aa87150768795816852c6393306893467ecaChet Haase 226df32aa87150768795816852c6393306893467ecaChet Haase /** 227df32aa87150768795816852c6393306893467ecaChet Haase * This private utility class is used to listen for both OnPreDraw and 228df32aa87150768795816852c6393306893467ecaChet Haase * OnAttachStateChange events. OnPreDraw events are the main ones we care 229df32aa87150768795816852c6393306893467ecaChet Haase * about since that's what triggers the transition to take place. 230df32aa87150768795816852c6393306893467ecaChet Haase * OnAttachStateChange events are also important in case the view is removed 231df32aa87150768795816852c6393306893467ecaChet Haase * from the hierarchy before the OnPreDraw event takes place; it's used to 232df32aa87150768795816852c6393306893467ecaChet Haase * clean up things since the OnPreDraw listener didn't get called in time. 233df32aa87150768795816852c6393306893467ecaChet Haase */ 234df32aa87150768795816852c6393306893467ecaChet Haase private static class MultiListener implements ViewTreeObserver.OnPreDrawListener, 235df32aa87150768795816852c6393306893467ecaChet Haase View.OnAttachStateChangeListener { 236df32aa87150768795816852c6393306893467ecaChet Haase 237df32aa87150768795816852c6393306893467ecaChet Haase Transition mTransition; 238df32aa87150768795816852c6393306893467ecaChet Haase ViewGroup mSceneRoot; 239df32aa87150768795816852c6393306893467ecaChet Haase 240df32aa87150768795816852c6393306893467ecaChet Haase MultiListener(Transition transition, ViewGroup sceneRoot) { 241df32aa87150768795816852c6393306893467ecaChet Haase mTransition = transition; 242df32aa87150768795816852c6393306893467ecaChet Haase mSceneRoot = sceneRoot; 243df32aa87150768795816852c6393306893467ecaChet Haase } 244df32aa87150768795816852c6393306893467ecaChet Haase 245df32aa87150768795816852c6393306893467ecaChet Haase private void removeListeners() { 246df32aa87150768795816852c6393306893467ecaChet Haase mSceneRoot.getViewTreeObserver().removeOnPreDrawListener(this); 247df32aa87150768795816852c6393306893467ecaChet Haase mSceneRoot.removeOnAttachStateChangeListener(this); 248df32aa87150768795816852c6393306893467ecaChet Haase } 249199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase 250df32aa87150768795816852c6393306893467ecaChet Haase @Override 251df32aa87150768795816852c6393306893467ecaChet Haase public void onViewAttachedToWindow(View v) { 252df32aa87150768795816852c6393306893467ecaChet Haase } 253df32aa87150768795816852c6393306893467ecaChet Haase 254df32aa87150768795816852c6393306893467ecaChet Haase @Override 255df32aa87150768795816852c6393306893467ecaChet Haase public void onViewDetachedFromWindow(View v) { 256df32aa87150768795816852c6393306893467ecaChet Haase removeListeners(); 257df32aa87150768795816852c6393306893467ecaChet Haase 258df32aa87150768795816852c6393306893467ecaChet Haase sPendingTransitions.remove(mSceneRoot); 259df32aa87150768795816852c6393306893467ecaChet Haase ArrayList<Transition> runningTransitions = getRunningTransitions().get(mSceneRoot); 260df32aa87150768795816852c6393306893467ecaChet Haase if (runningTransitions != null && runningTransitions.size() > 0) { 261df32aa87150768795816852c6393306893467ecaChet Haase for (Transition runningTransition : runningTransitions) { 262cf68aad3164303df59b2a669d186a94533c9c743George Mount runningTransition.resume(mSceneRoot); 263faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase } 264df32aa87150768795816852c6393306893467ecaChet Haase } 265df32aa87150768795816852c6393306893467ecaChet Haase mTransition.clearValues(true); 266faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase } 267df32aa87150768795816852c6393306893467ecaChet Haase 268df32aa87150768795816852c6393306893467ecaChet Haase @Override 269df32aa87150768795816852c6393306893467ecaChet Haase public boolean onPreDraw() { 270df32aa87150768795816852c6393306893467ecaChet Haase removeListeners(); 271df32aa87150768795816852c6393306893467ecaChet Haase sPendingTransitions.remove(mSceneRoot); 272df32aa87150768795816852c6393306893467ecaChet Haase // Add to running list, handle end to remove it 273df32aa87150768795816852c6393306893467ecaChet Haase final ArrayMap<ViewGroup, ArrayList<Transition>> runningTransitions = 274df32aa87150768795816852c6393306893467ecaChet Haase getRunningTransitions(); 275df32aa87150768795816852c6393306893467ecaChet Haase ArrayList<Transition> currentTransitions = runningTransitions.get(mSceneRoot); 276df32aa87150768795816852c6393306893467ecaChet Haase ArrayList<Transition> previousRunningTransitions = null; 277df32aa87150768795816852c6393306893467ecaChet Haase if (currentTransitions == null) { 278df32aa87150768795816852c6393306893467ecaChet Haase currentTransitions = new ArrayList<Transition>(); 279df32aa87150768795816852c6393306893467ecaChet Haase runningTransitions.put(mSceneRoot, currentTransitions); 280df32aa87150768795816852c6393306893467ecaChet Haase } else if (currentTransitions.size() > 0) { 281df32aa87150768795816852c6393306893467ecaChet Haase previousRunningTransitions = new ArrayList<Transition>(currentTransitions); 282df32aa87150768795816852c6393306893467ecaChet Haase } 283df32aa87150768795816852c6393306893467ecaChet Haase currentTransitions.add(mTransition); 284df32aa87150768795816852c6393306893467ecaChet Haase mTransition.addListener(new Transition.TransitionListenerAdapter() { 285df32aa87150768795816852c6393306893467ecaChet Haase @Override 286df32aa87150768795816852c6393306893467ecaChet Haase public void onTransitionEnd(Transition transition) { 287df32aa87150768795816852c6393306893467ecaChet Haase ArrayList<Transition> currentTransitions = 288df32aa87150768795816852c6393306893467ecaChet Haase runningTransitions.get(mSceneRoot); 289df32aa87150768795816852c6393306893467ecaChet Haase currentTransitions.remove(transition); 290df32aa87150768795816852c6393306893467ecaChet Haase } 291df32aa87150768795816852c6393306893467ecaChet Haase }); 292df32aa87150768795816852c6393306893467ecaChet Haase mTransition.captureValues(mSceneRoot, false); 293df32aa87150768795816852c6393306893467ecaChet Haase if (previousRunningTransitions != null) { 294df32aa87150768795816852c6393306893467ecaChet Haase for (Transition runningTransition : previousRunningTransitions) { 295cf68aad3164303df59b2a669d186a94533c9c743George Mount runningTransition.resume(mSceneRoot); 296df32aa87150768795816852c6393306893467ecaChet Haase } 297df32aa87150768795816852c6393306893467ecaChet Haase } 298df32aa87150768795816852c6393306893467ecaChet Haase mTransition.playTransition(mSceneRoot); 299df32aa87150768795816852c6393306893467ecaChet Haase 300df32aa87150768795816852c6393306893467ecaChet Haase return true; 301df32aa87150768795816852c6393306893467ecaChet Haase } 302df32aa87150768795816852c6393306893467ecaChet Haase }; 303faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase 3044f5072327d00822a2bfaff56df46cea2981ac90dChet Haase private static void sceneChangeSetup(ViewGroup sceneRoot, Transition transition) { 3054f5072327d00822a2bfaff56df46cea2981ac90dChet Haase 306c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase // Capture current values 307199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase ArrayList<Transition> runningTransitions = getRunningTransitions().get(sceneRoot); 3084f5072327d00822a2bfaff56df46cea2981ac90dChet Haase 309199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase if (runningTransitions != null && runningTransitions.size() > 0) { 310199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase for (Transition runningTransition : runningTransitions) { 311cf68aad3164303df59b2a669d186a94533c9c743George Mount runningTransition.pause(sceneRoot); 312199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase } 3134f5072327d00822a2bfaff56df46cea2981ac90dChet Haase } 3144f5072327d00822a2bfaff56df46cea2981ac90dChet Haase 315199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase if (transition != null) { 316199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase transition.captureValues(sceneRoot, true); 317c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase } 318c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase 3194f5072327d00822a2bfaff56df46cea2981ac90dChet Haase // Notify previous scene that it is being exited 320d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase Scene previousScene = Scene.getCurrentScene(sceneRoot); 3214f5072327d00822a2bfaff56df46cea2981ac90dChet Haase if (previousScene != null) { 3224f5072327d00822a2bfaff56df46cea2981ac90dChet Haase previousScene.exit(); 3234f5072327d00822a2bfaff56df46cea2981ac90dChet Haase } 3244f5072327d00822a2bfaff56df46cea2981ac90dChet Haase } 3254f5072327d00822a2bfaff56df46cea2981ac90dChet Haase 326faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase /** 327faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * Change to the given scene, using the 328faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * appropriate transition for this particular scene change 329faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * (as specified to the TransitionManager, or the default 330faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * if no such transition exists). 331faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * 332faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * @param scene The Scene to change to 333faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase */ 334faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase public void transitionTo(Scene scene) { 335faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase // Auto transition if there is no transition declared for the Scene, but there is 336faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase // a root or parent view 337faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase changeScene(scene, getTransition(scene)); 338faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase } 339faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase 340faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase /** 341d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * Convenience method to simply change to the given scene using 342faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * the default transition for TransitionManager. 343faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * 344faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * @param scene The Scene to change to 345faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase */ 346faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase public static void go(Scene scene) { 347faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase changeScene(scene, sDefaultTransition); 348faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase } 349faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase 350faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase /** 351d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * Convenience method to simply change to the given scene using 352faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * the given transition. 353faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * 354faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * <p>Passing in <code>null</code> for the transition parameter will 355faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * result in the scene changing without any transition running, and is 356faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * equivalent to calling {@link Scene#exit()} on the scene root's 357d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * current scene, followed by {@link Scene#enter()} on the scene 358d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * specified by the <code>scene</code> parameter.</p> 359faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * 360faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * @param scene The Scene to change to 361faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * @param transition The transition to use for this scene change. A 362faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * value of null causes the scene change to happen with no transition. 363faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase */ 364faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase public static void go(Scene scene, Transition transition) { 365faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase changeScene(scene, transition); 366faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase } 367faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase 368faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase /** 369d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * Convenience method to animate, using the default transition, 370d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * to a new scene defined by all changes within the given scene root between 371d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * calling this method and the next rendering frame. 372d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * Equivalent to calling {@link #beginDelayedTransition(ViewGroup, Transition)} 373d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * with a value of <code>null</code> for the <code>transition</code> parameter. 374faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * 375faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * @param sceneRoot The root of the View hierarchy to run the transition on. 376faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase */ 377d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase public static void beginDelayedTransition(final ViewGroup sceneRoot) { 378d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase beginDelayedTransition(sceneRoot, null); 379faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase } 3804f5072327d00822a2bfaff56df46cea2981ac90dChet Haase 3814f5072327d00822a2bfaff56df46cea2981ac90dChet Haase /** 382d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * Convenience method to animate to a new scene defined by all changes within 3834f5072327d00822a2bfaff56df46cea2981ac90dChet Haase * the given scene root between calling this method and the next rendering frame. 3844f5072327d00822a2bfaff56df46cea2981ac90dChet Haase * Calling this method causes TransitionManager to capture current values in the 3854f5072327d00822a2bfaff56df46cea2981ac90dChet Haase * scene root and then post a request to run a transition on the next frame. 3864f5072327d00822a2bfaff56df46cea2981ac90dChet Haase * At that time, the new values in the scene root will be captured and changes 3874f5072327d00822a2bfaff56df46cea2981ac90dChet Haase * will be animated. There is no need to create a Scene; it is implied by 3884f5072327d00822a2bfaff56df46cea2981ac90dChet Haase * changes which take place between calling this method and the next frame when 3894f5072327d00822a2bfaff56df46cea2981ac90dChet Haase * the transition begins. 3904f5072327d00822a2bfaff56df46cea2981ac90dChet Haase * 3914f5072327d00822a2bfaff56df46cea2981ac90dChet Haase * <p>Calling this method several times before the next frame (for example, if 3924f5072327d00822a2bfaff56df46cea2981ac90dChet Haase * unrelated code also wants to make dynamic changes and run a transition on 3934f5072327d00822a2bfaff56df46cea2981ac90dChet Haase * the same scene root), only the first call will trigger capturing values 3944f5072327d00822a2bfaff56df46cea2981ac90dChet Haase * and exiting the current scene. Subsequent calls to the method with the 3954f5072327d00822a2bfaff56df46cea2981ac90dChet Haase * same scene root during the same frame will be ignored.</p> 3964f5072327d00822a2bfaff56df46cea2981ac90dChet Haase * 3974f5072327d00822a2bfaff56df46cea2981ac90dChet Haase * <p>Passing in <code>null</code> for the transition parameter will 3984f5072327d00822a2bfaff56df46cea2981ac90dChet Haase * cause the TransitionManager to use its default transition.</p> 3994f5072327d00822a2bfaff56df46cea2981ac90dChet Haase * 4004f5072327d00822a2bfaff56df46cea2981ac90dChet Haase * @param sceneRoot The root of the View hierarchy to run the transition on. 4014f5072327d00822a2bfaff56df46cea2981ac90dChet Haase * @param transition The transition to use for this change. A 4024f5072327d00822a2bfaff56df46cea2981ac90dChet Haase * value of null causes the TransitionManager to use the default transition. 4034f5072327d00822a2bfaff56df46cea2981ac90dChet Haase */ 4044f5072327d00822a2bfaff56df46cea2981ac90dChet Haase public static void beginDelayedTransition(final ViewGroup sceneRoot, Transition transition) { 40523c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase if (!sPendingTransitions.contains(sceneRoot) && sceneRoot.isLaidOut()) { 40623c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase if (Transition.DBG) { 40723c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase Log.d(LOG_TAG, "beginDelayedTransition: root, transition = " + 40823c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase sceneRoot + ", " + transition); 40923c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase } 41023c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase sPendingTransitions.add(sceneRoot); 41123c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase if (transition == null) { 41223c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase transition = sDefaultTransition; 41323c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase } 41423c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase final Transition transitionClone = transition.clone(); 41523c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase sceneChangeSetup(sceneRoot, transitionClone); 41623c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase Scene.setCurrentScene(sceneRoot, null); 41723c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase sceneChangeRunTransition(sceneRoot, transitionClone); 41823c61f6bc57a611d97d333bce0d8fe00ab81af4cChet Haase } 4194f5072327d00822a2bfaff56df46cea2981ac90dChet Haase } 420faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase} 421