1c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki/*
2c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * Copyright (C) 2016 The Android Open Source Project
3c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki *
4c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * Licensed under the Apache License, Version 2.0 (the "License");
5c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * you may not use this file except in compliance with the License.
6c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * You may obtain a copy of the License at
7c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki *
8c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki *      http://www.apache.org/licenses/LICENSE-2.0
9c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki *
10c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * Unless required by applicable law or agreed to in writing, software
11c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * distributed under the License is distributed on an "AS IS" BASIS,
12c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * See the License for the specific language governing permissions and
14c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * limitations under the License.
15c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki */
16c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
17c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakipackage android.support.transition;
18c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
19c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport android.content.Context;
20c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport android.os.Build;
21cbba0a52f7d7b593dbb13a138515f066f75cce80Yuichi Arakiimport android.support.annotation.LayoutRes;
22cbba0a52f7d7b593dbb13a138515f066f75cce80Yuichi Arakiimport android.support.annotation.NonNull;
23cbba0a52f7d7b593dbb13a138515f066f75cce80Yuichi Arakiimport android.support.annotation.Nullable;
24c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport android.util.SparseArray;
25c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport android.view.View;
26c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport android.view.ViewGroup;
27c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
28c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki/**
29c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * A scene represents the collection of values that various properties in the
30c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * View hierarchy will have when the scene is applied. A Scene can be
31c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * configured to automatically run a Transition when it is applied, which will
32c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * animate the various property changes that take place during the
33c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * scene change.
34c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki */
35c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakipublic class Scene {
36c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
37c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    private static SceneStaticsImpl sImpl;
38c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
39c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    static {
40bd6c3bc3b3bc69f629b11218fbdd2bf171f74d7dYuichi Araki        if (Build.VERSION.SDK_INT >= 21) {
41bd6c3bc3b3bc69f629b11218fbdd2bf171f74d7dYuichi Araki            sImpl = new SceneStaticsApi21();
42bd6c3bc3b3bc69f629b11218fbdd2bf171f74d7dYuichi Araki        } else if (Build.VERSION.SDK_INT >= 19) {
43c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            sImpl = new SceneStaticsKitKat();
44bd6c3bc3b3bc69f629b11218fbdd2bf171f74d7dYuichi Araki        } else {
45bd6c3bc3b3bc69f629b11218fbdd2bf171f74d7dYuichi Araki            sImpl = new SceneStaticsIcs();
46c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        }
47c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    }
48c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
49c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    /* package */ SceneImpl mImpl;
50c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
51c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    /**
52c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * Constructs a Scene with no information about how values will change
53c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * when this scene is applied. This constructor might be used when
54c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * a Scene is created with the intention of being dynamically configured,
55c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * through setting {@link #setEnterAction(Runnable)} and possibly
56c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * {@link #setExitAction(Runnable)}.
57c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     *
58c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * @param sceneRoot The root of the hierarchy in which scene changes
59c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     *                  and transitions will take place.
60c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     */
61cbba0a52f7d7b593dbb13a138515f066f75cce80Yuichi Araki    public Scene(@NonNull ViewGroup sceneRoot) {
62c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        mImpl = createSceneImpl();
63c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        mImpl.init(sceneRoot);
64c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    }
65c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
66c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    /**
67c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * Constructs a Scene which, when entered, will remove any
68c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * children from the sceneRoot container and add the layout
69c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * object as a new child of that container.
70c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     *
71c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * @param sceneRoot The root of the hierarchy in which scene changes
72c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     *                  and transitions will take place.
73c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * @param layout    The view hierarchy of this scene, added as a child
74c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     *                  of sceneRoot when this scene is entered.
75c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     */
76cbba0a52f7d7b593dbb13a138515f066f75cce80Yuichi Araki    public Scene(@NonNull ViewGroup sceneRoot, @NonNull View layout) {
77c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        mImpl = createSceneImpl();
78c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        mImpl.init(sceneRoot, layout);
79c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    }
80c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
81c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    private Scene(SceneImpl scene) {
82c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        mImpl = scene;
83c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    }
84c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
85c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    /**
86c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * Returns a Scene described by the resource file associated with the given
87c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * <code>layoutId</code> parameter. If such a Scene has already been created for
88c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * the given <code>sceneRoot</code>, that same Scene will be returned.
89c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * This caching of layoutId-based scenes enables sharing of common scenes
90c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * between those created in code and those referenced by {@link TransitionManager}
91c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * XML resource files.
92c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     *
93c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * @param sceneRoot The root of the hierarchy in which scene changes
94c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     *                  and transitions will take place.
95c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * @param layoutId  The id of a standard layout resource file.
96c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * @param context   The context used in the process of inflating
97c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     *                  the layout resource.
98c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * @return The scene for the given root and layout id
99c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     */
100cbba0a52f7d7b593dbb13a138515f066f75cce80Yuichi Araki    @NonNull
101cbba0a52f7d7b593dbb13a138515f066f75cce80Yuichi Araki    public static Scene getSceneForLayout(@NonNull ViewGroup sceneRoot, @LayoutRes int layoutId,
102cbba0a52f7d7b593dbb13a138515f066f75cce80Yuichi Araki            @NonNull Context context) {
103c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        @SuppressWarnings("unchecked")
104c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        SparseArray<Scene> scenes =
105c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                (SparseArray<Scene>) sceneRoot.getTag(R.id.transition_scene_layoutid_cache);
106c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        if (scenes == null) {
107c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            scenes = new SparseArray<>();
108c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            sceneRoot.setTag(R.id.transition_scene_layoutid_cache, scenes);
109c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        }
110c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        Scene scene = scenes.get(layoutId);
111c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        if (scene != null) {
112c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            return scene;
113c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        } else {
114c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            scene = new Scene(sImpl.getSceneForLayout(sceneRoot, layoutId, context));
115c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            scenes.put(layoutId, scene);
116c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            return scene;
117c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        }
118c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    }
119c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
120c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    private SceneImpl createSceneImpl() {
121bd6c3bc3b3bc69f629b11218fbdd2bf171f74d7dYuichi Araki        if (Build.VERSION.SDK_INT >= 21) {
122bd6c3bc3b3bc69f629b11218fbdd2bf171f74d7dYuichi Araki            return new SceneApi21();
123bd6c3bc3b3bc69f629b11218fbdd2bf171f74d7dYuichi Araki        } else if (Build.VERSION.SDK_INT >= 19) {
124c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            return new SceneKitKat();
125bd6c3bc3b3bc69f629b11218fbdd2bf171f74d7dYuichi Araki        } else {
126bd6c3bc3b3bc69f629b11218fbdd2bf171f74d7dYuichi Araki            return new SceneIcs();
127c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        }
128c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    }
129c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
130c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    /**
131c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * Gets the root of the scene, which is the root of the view hierarchy
132c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * affected by changes due to this scene, and which will be animated
133c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * when this scene is entered.
134c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     *
135c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * @return The root of the view hierarchy affected by this scene.
136c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     */
137cbba0a52f7d7b593dbb13a138515f066f75cce80Yuichi Araki    @NonNull
138c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    public ViewGroup getSceneRoot() {
139c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        return mImpl.getSceneRoot();
140c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    }
141c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
142c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    /**
143c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * Exits this scene, if it is the current scene
144c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * on the scene's {@link #getSceneRoot() scene root}. The current scene is
145c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * set when {@link #enter() entering} a scene.
146c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * Exiting a scene runs the {@link #setExitAction(Runnable) exit action}
147c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * if there is one.
148c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     */
149c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    public void exit() {
150c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        mImpl.exit();
151c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    }
152c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
153c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    /**
154c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * Enters this scene, which entails changing all values that
155c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * are specified by this scene. These may be values associated
156c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * with a layout view group or layout resource file which will
157c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * now be added to the scene root, or it may be values changed by
158c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * an {@link #setEnterAction(Runnable)} enter action}, or a
159c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * combination of the these. No transition will be run when the
160c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * scene is entered. To get transition behavior in scene changes,
161c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * use one of the methods in {@link android.support.transition.TransitionManager} instead.
162c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     */
163c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    public void enter() {
164c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        mImpl.enter();
165c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    }
166c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
167c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    /**
168c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * Scenes that are not defined with layout resources or
169c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * hierarchies, or which need to perform additional steps
170c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * after those hierarchies are changed to, should set an enter
171c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * action, and possibly an exit action as well. An enter action
172c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * will cause Scene to call back into application code to do
173c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * anything else the application needs after transitions have
174c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * captured pre-change values and after any other scene changes
175c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * have been applied, such as the layout (if any) being added to
176c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * the view hierarchy. After this method is called, Transitions will
177c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * be played.
178c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     *
179c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * @param action The runnable whose {@link Runnable#run() run()} method will
180c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     *               be called when this scene is entered
181c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * @see #setExitAction(Runnable)
182c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * @see android.support.transition.Scene(android.view.ViewGroup, android.view.ViewGroup)
183c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     */
184cbba0a52f7d7b593dbb13a138515f066f75cce80Yuichi Araki    public void setEnterAction(@Nullable Runnable action) {
185c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        mImpl.setEnterAction(action);
186c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    }
187c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
188c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    /**
189c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * Scenes that are not defined with layout resources or
190c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * hierarchies, or which need to perform additional steps
191c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * after those hierarchies are changed to, should set an enter
192c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * action, and possibly an exit action as well. An exit action
193c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * will cause Scene to call back into application code to do
194c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * anything the application needs to do after applicable transitions have
195c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * captured pre-change values, but before any other scene changes
196c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * have been applied, such as the new layout (if any) being added to
197c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * the view hierarchy. After this method is called, the next scene
198c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * will be entered, including a call to {@link #setEnterAction(Runnable)}
199c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * if an enter action is set.
200c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     *
201c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * @see #setEnterAction(Runnable)
202c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * @see android.support.transition.Scene(android.view.ViewGroup, android.view.ViewGroup)
203c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     */
204cbba0a52f7d7b593dbb13a138515f066f75cce80Yuichi Araki    public void setExitAction(@Nullable Runnable action) {
205c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        mImpl.setExitAction(action);
206c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    }
207c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
208c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki}
209