14500be62dea3895a98336122a2944cc4ab024bc5George Mount/*
24500be62dea3895a98336122a2944cc4ab024bc5George Mount * Copyright (C) 2014 The Android Open Source Project
34500be62dea3895a98336122a2944cc4ab024bc5George Mount *
44500be62dea3895a98336122a2944cc4ab024bc5George Mount * Licensed under the Apache License, Version 2.0 (the "License");
54500be62dea3895a98336122a2944cc4ab024bc5George Mount * you may not use this file except in compliance with the License.
64500be62dea3895a98336122a2944cc4ab024bc5George Mount * You may obtain a copy of the License at
74500be62dea3895a98336122a2944cc4ab024bc5George Mount *
84500be62dea3895a98336122a2944cc4ab024bc5George Mount *      http://www.apache.org/licenses/LICENSE-2.0
94500be62dea3895a98336122a2944cc4ab024bc5George Mount *
104500be62dea3895a98336122a2944cc4ab024bc5George Mount * Unless required by applicable law or agreed to in writing, software
114500be62dea3895a98336122a2944cc4ab024bc5George Mount * distributed under the License is distributed on an "AS IS" BASIS,
124500be62dea3895a98336122a2944cc4ab024bc5George Mount * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134500be62dea3895a98336122a2944cc4ab024bc5George Mount * See the License for the specific language governing permissions and
144500be62dea3895a98336122a2944cc4ab024bc5George Mount * limitations under the License.
154500be62dea3895a98336122a2944cc4ab024bc5George Mount */
164500be62dea3895a98336122a2944cc4ab024bc5George Mount
174500be62dea3895a98336122a2944cc4ab024bc5George Mountpackage android.support.v4.app;
184500be62dea3895a98336122a2944cc4ab024bc5George Mount
199f4a046cbeb22a24d322a644323b41022ad9d15aGeorge Mountimport android.graphics.Rect;
208f886fe8c7e23fe6ccb8734167c960c2ed3429c3Alan Viveretteimport android.support.annotation.RequiresApi;
219f4a046cbeb22a24d322a644323b41022ad9d15aGeorge Mountimport android.transition.Transition;
229f4a046cbeb22a24d322a644323b41022ad9d15aGeorge Mountimport android.transition.TransitionManager;
239f4a046cbeb22a24d322a644323b41022ad9d15aGeorge Mountimport android.transition.TransitionSet;
244500be62dea3895a98336122a2944cc4ab024bc5George Mountimport android.view.View;
254500be62dea3895a98336122a2944cc4ab024bc5George Mountimport android.view.ViewGroup;
264500be62dea3895a98336122a2944cc4ab024bc5George Mount
274500be62dea3895a98336122a2944cc4ab024bc5George Mountimport java.util.ArrayList;
28c766ad5a6e0c115f08b933ede22375c7070a3391George Mountimport java.util.List;
299f4a046cbeb22a24d322a644323b41022ad9d15aGeorge Mountimport java.util.Map;
304500be62dea3895a98336122a2944cc4ab024bc5George Mount
318f886fe8c7e23fe6ccb8734167c960c2ed3429c3Alan Viverette@RequiresApi(21)
324500be62dea3895a98336122a2944cc4ab024bc5George Mountclass FragmentTransitionCompat21 {
334500be62dea3895a98336122a2944cc4ab024bc5George Mount
34990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    /**
35990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * Returns a clone of a transition or null if it is null
36990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     */
370f5ae57910484f1d873fdad90966b6244a633bd4George Mount    public static Object cloneTransition(Object transition) {
38990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        Transition copy = null;
390f5ae57910484f1d873fdad90966b6244a633bd4George Mount        if (transition != null) {
40990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            copy = ((Transition) transition).clone();
414500be62dea3895a98336122a2944cc4ab024bc5George Mount        }
42990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        return copy;
434500be62dea3895a98336122a2944cc4ab024bc5George Mount    }
444500be62dea3895a98336122a2944cc4ab024bc5George Mount
45990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    /**
46990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * Wraps a transition in a TransitionSet and returns the set. If transition is null, null is
47990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * returned.
48990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     */
49990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    public static Object wrapTransitionInSet(Object transition) {
50c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount        if (transition == null) {
51c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount            return null;
52c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount        }
53c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount        TransitionSet transitionSet = new TransitionSet();
54990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        transitionSet.addTransition((Transition) transition);
55c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount        return transitionSet;
56c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount    }
57c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount
58c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount    /**
59c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount     * Finds all children of the shared elements and sets the wrapping TransitionSet
60c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount     * targets to point to those. It also limits transitions that have no targets to the
61c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount     * specific shared elements. This allows developers to target child views of the
62c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount     * shared elements specifically, but this doesn't happen by default.
63c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount     */
64c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount    public static void setSharedElementTargets(Object transitionObj,
65990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            View nonExistentView, ArrayList<View> sharedViews) {
66c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount        TransitionSet transition = (TransitionSet) transitionObj;
67c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount        final List<View> views = transition.getTargets();
68c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount        views.clear();
69990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        final int count = sharedViews.size();
70c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount        for (int i = 0; i < count; i++) {
71990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            final View view = sharedViews.get(i);
72c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount            bfsAddViewChildren(views, view);
73c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount        }
74990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        views.add(nonExistentView);
75990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        sharedViews.add(nonExistentView);
76990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        addTargets(transition, sharedViews);
77c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount    }
789f4a046cbeb22a24d322a644323b41022ad9d15aGeorge Mount
79c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount    /**
80c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount     * Uses a breadth-first scheme to add startView and all of its children to views.
81c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount     * It won't add a child if it is already in views.
82c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount     */
83c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount    private static void bfsAddViewChildren(final List<View> views, final View startView) {
84c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount        final int startIndex = views.size();
85c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount        if (containedBeforeIndex(views, startView, startIndex)) {
86c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount            return; // This child is already in the list, so all its children are also.
87c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount        }
88c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount        views.add(startView);
89c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount        for (int index = startIndex; index < views.size(); index++) {
90c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount            final View view = views.get(index);
91c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount            if (view instanceof ViewGroup) {
92c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount                ViewGroup viewGroup = (ViewGroup) view;
93c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount                final int childCount =  viewGroup.getChildCount();
94c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount                for (int childIndex = 0; childIndex < childCount; childIndex++) {
95c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount                    final View child = viewGroup.getChildAt(childIndex);
96c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount                    if (!containedBeforeIndex(views, child, startIndex)) {
97c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount                        views.add(child);
98c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount                    }
99c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount                }
100c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount            }
101c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount        }
102c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount    }
103c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount
104c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount    /**
105c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount     * Does a linear search through views for view, limited to maxIndex.
106c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount     */
107c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount    private static boolean containedBeforeIndex(final List<View> views, final View view,
108c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount            final int maxIndex) {
109c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount        for (int i = 0; i < maxIndex; i++) {
110c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount            if (views.get(i) == view) {
111c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount                return true;
112c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount            }
113c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount        }
114c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount        return false;
115c33885b865c99ce9ae96214f0e9d7bd1ca12cb93George Mount    }
1169f4a046cbeb22a24d322a644323b41022ad9d15aGeorge Mount
117990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    /**
118990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * Sets a transition epicenter to the rectangle of a given View.
119990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     */
120990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    public static void setEpicenter(Object transitionObj, View view) {
121990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        if (view != null) {
122990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            Transition transition = (Transition) transitionObj;
123990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            final Rect epicenter = new Rect();
124990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            getBoundsOnScreen(view, epicenter);
1250f5ae57910484f1d873fdad90966b6244a633bd4George Mount
126990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            transition.setEpicenterCallback(new Transition.EpicenterCallback() {
1270f5ae57910484f1d873fdad90966b6244a633bd4George Mount                @Override
1280f5ae57910484f1d873fdad90966b6244a633bd4George Mount                public Rect onGetEpicenter(Transition transition) {
129990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                    return epicenter;
1304500be62dea3895a98336122a2944cc4ab024bc5George Mount                }
1310f5ae57910484f1d873fdad90966b6244a633bd4George Mount            });
1320f5ae57910484f1d873fdad90966b6244a633bd4George Mount        }
1334500be62dea3895a98336122a2944cc4ab024bc5George Mount    }
1344500be62dea3895a98336122a2944cc4ab024bc5George Mount
135990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    /**
136990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * Replacement for view.getBoundsOnScreen because that is not public. This returns a rect
137990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * containing the bounds relative to the screen that the view is in.
138990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     */
139990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    public static void getBoundsOnScreen(View view, Rect epicenter) {
1404500be62dea3895a98336122a2944cc4ab024bc5George Mount        int[] loc = new int[2];
1414500be62dea3895a98336122a2944cc4ab024bc5George Mount        view.getLocationOnScreen(loc);
1424500be62dea3895a98336122a2944cc4ab024bc5George Mount        epicenter.set(loc[0], loc[1], loc[0] + view.getWidth(), loc[1] + view.getHeight());
1434500be62dea3895a98336122a2944cc4ab024bc5George Mount    }
1444500be62dea3895a98336122a2944cc4ab024bc5George Mount
145990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    /**
146990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * This method adds views as targets to the transition, but only if the transition
147990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * doesn't already have a target. It is best for views to contain one View object
148990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * that does not exist in the view hierarchy (state.nonExistentView) so that
149990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * when they are removed later, a list match will suffice to remove the targets.
150990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * Otherwise, if you happened to have targeted the exact views for the transition,
151990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * the replaceTargets call will remove them unexpectedly.
152990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     */
153990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    public static void addTargets(Object transitionObj, ArrayList<View> views) {
154990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        Transition transition = (Transition) transitionObj;
155990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        if (transition == null) {
156990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            return;
157990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        }
158990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        if (transition instanceof TransitionSet) {
159990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            TransitionSet set = (TransitionSet) transition;
160990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            int numTransitions = set.getTransitionCount();
161990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            for (int i = 0; i < numTransitions; i++) {
162990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                Transition child = set.getTransitionAt(i);
163990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                addTargets(child, views);
164990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            }
165990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        } else if (!hasSimpleTarget(transition)) {
166990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            List<View> targets = transition.getTargets();
167990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            if (isNullOrEmpty(targets)) {
168990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                // We can just add the target views
169990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                int numViews = views.size();
170990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                for (int i = 0; i < numViews; i++) {
171990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                    transition.addTarget(views.get(i));
172990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                }
173990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            }
174990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        }
175990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    }
176990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount
177990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    /**
178990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * Returns true if there are any targets based on ID, transition or type.
179990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     */
180990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    private static boolean hasSimpleTarget(Transition transition) {
181990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        return !isNullOrEmpty(transition.getTargetIds())
182990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                || !isNullOrEmpty(transition.getTargetNames())
183990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                || !isNullOrEmpty(transition.getTargetTypes());
184990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    }
185990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount
186990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    /**
187990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * Simple utility to detect if a list is null or has no elements.
188990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     */
189990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    private static boolean isNullOrEmpty(List list) {
190990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        return list == null || list.isEmpty();
191990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    }
192990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount
193990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    /**
194990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * Creates a TransitionSet that plays all passed transitions together. Any null
195990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * transitions passed will not be added to the set. If all are null, then an empty
196990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * TransitionSet will be returned.
197990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     */
198990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    public static Object mergeTransitionsTogether(Object transition1, Object transition2,
199990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            Object transition3) {
200990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        TransitionSet transitionSet = new TransitionSet();
201990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        if (transition1 != null) {
202990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            transitionSet.addTransition((Transition) transition1);
203990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        }
204990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        if (transition2 != null) {
205990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            transitionSet.addTransition((Transition) transition2);
206990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        }
207990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        if (transition3 != null) {
208990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            transitionSet.addTransition((Transition) transition3);
209990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        }
210990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        return transitionSet;
211990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    }
212990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount
213990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    /**
214667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount     * After the transition completes, the fragment's view is set to GONE and the exiting
215667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount     * views are set to VISIBLE.
216667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount     */
217667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount    public static void scheduleHideFragmentView(Object exitTransitionObj, final View fragmentView,
218667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount            final ArrayList<View> exitingViews) {
219667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount        Transition exitTransition = (Transition) exitTransitionObj;
220667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount        exitTransition.addListener(new Transition.TransitionListener() {
221667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount            @Override
222667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount            public void onTransitionStart(Transition transition) {
223667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount            }
224667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount
225667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount            @Override
226667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount            public void onTransitionEnd(Transition transition) {
227667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount                transition.removeListener(this);
228667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount                fragmentView.setVisibility(View.GONE);
229667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount                final int numViews = exitingViews.size();
230667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount                for (int i = 0; i < numViews; i++) {
231667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount                    exitingViews.get(i).setVisibility(View.VISIBLE);
232667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount                }
233667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount            }
234667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount
235667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount            @Override
236667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount            public void onTransitionCancel(Transition transition) {
237667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount            }
238667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount
239667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount            @Override
240667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount            public void onTransitionPause(Transition transition) {
241667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount            }
242667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount
243667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount            @Override
244667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount            public void onTransitionResume(Transition transition) {
245667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount            }
246667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount        });
247667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount    }
248667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount
249667ec4150c78bf295b3db1fa4d546def9ade9d20George Mount    /**
250990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * Combines enter, exit, and shared element transition so that they play in the proper
251990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * sequence. First the exit transition plays along with the shared element transition.
252990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * When the exit transition completes, the enter transition starts. The shared element
253990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * transition can continue running while the enter transition plays.
254990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     *
255990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * @return A TransitionSet with all of enter, exit, and shared element transitions in
256990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * it (modulo null values), ordered such that they play in the proper sequence.
257990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     */
258990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    public static Object mergeTransitionsInSequence(Object exitTransitionObj,
259990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            Object enterTransitionObj, Object sharedElementTransitionObj) {
260990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        // First do exit, then enter, but allow shared element transition to happen
261990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        // during both.
262990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        Transition staggered = null;
263990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        final Transition exitTransition = (Transition) exitTransitionObj;
264990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        final Transition enterTransition = (Transition) enterTransitionObj;
265990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        final Transition sharedElementTransition = (Transition) sharedElementTransitionObj;
266990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        if (exitTransition != null && enterTransition != null) {
267990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            staggered = new TransitionSet()
268990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                    .addTransition(exitTransition)
269990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                    .addTransition(enterTransition)
270990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                    .setOrdering(TransitionSet.ORDERING_SEQUENTIAL);
271990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        } else if (exitTransition != null) {
272990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            staggered = exitTransition;
273990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        } else if (enterTransition != null) {
274990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            staggered = enterTransition;
275990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        }
276990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        if (sharedElementTransition != null) {
277990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            TransitionSet together = new TransitionSet();
278990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            if (staggered != null) {
279990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                together.addTransition(staggered);
280990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            }
281990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            together.addTransition(sharedElementTransition);
282990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            return together;
283990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        } else {
284990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            return staggered;
285990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        }
286990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    }
287990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount
288990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    /**
289990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * Calls {@link TransitionManager#beginDelayedTransition(ViewGroup, Transition)}.
290990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     */
291990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    public static void beginDelayedTransition(ViewGroup sceneRoot, Object transition) {
292990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        TransitionManager.beginDelayedTransition(sceneRoot, (Transition) transition);
293990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    }
294990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount
295990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    /**
296990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * Prepares for setting the shared element names by gathering the names of the incoming
297fda5be2466024a656152015c45a7681361d399bbGeorge Mount     * shared elements and clearing them. {@link #setNameOverridesReordered(View, ArrayList,
298990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * ArrayList, ArrayList, Map)} must be called after this to complete setting the shared element
299990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * name overrides. This must be called before
300990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * {@link #beginDelayedTransition(ViewGroup, Object)}.
301990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     */
302fda5be2466024a656152015c45a7681361d399bbGeorge Mount    public static ArrayList<String> prepareSetNameOverridesReordered(
303990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            final ArrayList<View> sharedElementsIn) {
304990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        final ArrayList<String> names = new ArrayList<>();
305990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        final int numSharedElements = sharedElementsIn.size();
306990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        for (int i = 0; i < numSharedElements; i++) {
307990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            final View view = sharedElementsIn.get(i);
308990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            names.add(view.getTransitionName());
309990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            view.setTransitionName(null);
310990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        }
311990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        return names;
312990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    }
313990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount
314990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    /**
315990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * Changes the shared element names for the incoming shared eleemnts to match those of the
316990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * outgoing shared elements. This also temporarily clears the shared element names of the
317990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * outgoing shared elements. Must be called after
318990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * {@link #beginDelayedTransition(ViewGroup, Object)}.
319990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     */
320fda5be2466024a656152015c45a7681361d399bbGeorge Mount    public static void setNameOverridesReordered(final View sceneRoot,
321990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            final ArrayList<View> sharedElementsOut, final ArrayList<View> sharedElementsIn,
322990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            final ArrayList<String> inNames, final Map<String, String> nameOverrides) {
323990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        final int numSharedElements = sharedElementsIn.size();
324990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        final ArrayList<String> outNames = new ArrayList<>();
325990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount
326990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        for (int i = 0; i < numSharedElements; i++) {
327990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            final View view = sharedElementsOut.get(i);
328990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            final String name = view.getTransitionName();
329990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            outNames.add(name);
330990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            if (name == null) {
331990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                continue;
332990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            }
333990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            view.setTransitionName(null);
334990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            final String inName = nameOverrides.get(name);
335990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            for (int j = 0; j < numSharedElements; j++) {
336990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                if (inName.equals(inNames.get(j))) {
337990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                    sharedElementsIn.get(j).setTransitionName(name);
338990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                    break;
339990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                }
340990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            }
341990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        }
342990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount
3437d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount        OneShotPreDrawListener.add(sceneRoot, new Runnable() {
3447d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount            @Override
3457d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount            public void run() {
3467d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount                for (int i = 0; i < numSharedElements; i++) {
3477d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount                    sharedElementsIn.get(i).setTransitionName(inNames.get(i));
3487d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount                    sharedElementsOut.get(i).setTransitionName(outNames.get(i));
3497d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount                }
3507d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount            }
3517d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount        });
352990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    }
353990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount
354990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    /**
355990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions.
356990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and
357990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     *                           a normal View or a ViewGroup with
358990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     *                           {@link android.view.ViewGroup#isTransitionGroup()} true.
359990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * @param view The base of the view hierarchy to look in.
360990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     */
361990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    public static void captureTransitioningViews(ArrayList<View> transitioningViews, View view) {
3624500be62dea3895a98336122a2944cc4ab024bc5George Mount        if (view.getVisibility() == View.VISIBLE) {
3634500be62dea3895a98336122a2944cc4ab024bc5George Mount            if (view instanceof ViewGroup) {
3644500be62dea3895a98336122a2944cc4ab024bc5George Mount                ViewGroup viewGroup = (ViewGroup) view;
3654500be62dea3895a98336122a2944cc4ab024bc5George Mount                if (viewGroup.isTransitionGroup()) {
3664500be62dea3895a98336122a2944cc4ab024bc5George Mount                    transitioningViews.add(viewGroup);
3674500be62dea3895a98336122a2944cc4ab024bc5George Mount                } else {
3684500be62dea3895a98336122a2944cc4ab024bc5George Mount                    int count = viewGroup.getChildCount();
3694500be62dea3895a98336122a2944cc4ab024bc5George Mount                    for (int i = 0; i < count; i++) {
3704500be62dea3895a98336122a2944cc4ab024bc5George Mount                        View child = viewGroup.getChildAt(i);
3714500be62dea3895a98336122a2944cc4ab024bc5George Mount                        captureTransitioningViews(transitioningViews, child);
3724500be62dea3895a98336122a2944cc4ab024bc5George Mount                    }
3734500be62dea3895a98336122a2944cc4ab024bc5George Mount                }
3744500be62dea3895a98336122a2944cc4ab024bc5George Mount            } else {
3754500be62dea3895a98336122a2944cc4ab024bc5George Mount                transitioningViews.add(view);
3764500be62dea3895a98336122a2944cc4ab024bc5George Mount            }
3774500be62dea3895a98336122a2944cc4ab024bc5George Mount        }
3784500be62dea3895a98336122a2944cc4ab024bc5George Mount    }
3794500be62dea3895a98336122a2944cc4ab024bc5George Mount
380990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    /**
381990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * Finds all views that have transition names in the hierarchy under the given view and
382990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * stores them in {@code namedViews} map with the name as the key.
383990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     */
3849f4a046cbeb22a24d322a644323b41022ad9d15aGeorge Mount    public static void findNamedViews(Map<String, View> namedViews, View view) {
3854500be62dea3895a98336122a2944cc4ab024bc5George Mount        if (view.getVisibility() == View.VISIBLE) {
3864500be62dea3895a98336122a2944cc4ab024bc5George Mount            String transitionName = view.getTransitionName();
3874500be62dea3895a98336122a2944cc4ab024bc5George Mount            if (transitionName != null) {
3884500be62dea3895a98336122a2944cc4ab024bc5George Mount                namedViews.put(transitionName, view);
3894500be62dea3895a98336122a2944cc4ab024bc5George Mount            }
3904500be62dea3895a98336122a2944cc4ab024bc5George Mount            if (view instanceof ViewGroup) {
3914500be62dea3895a98336122a2944cc4ab024bc5George Mount                ViewGroup viewGroup = (ViewGroup) view;
3924500be62dea3895a98336122a2944cc4ab024bc5George Mount                int count = viewGroup.getChildCount();
3934500be62dea3895a98336122a2944cc4ab024bc5George Mount                for (int i = 0; i < count; i++) {
3944500be62dea3895a98336122a2944cc4ab024bc5George Mount                    View child = viewGroup.getChildAt(i);
3954500be62dea3895a98336122a2944cc4ab024bc5George Mount                    findNamedViews(namedViews, child);
3964500be62dea3895a98336122a2944cc4ab024bc5George Mount                }
3974500be62dea3895a98336122a2944cc4ab024bc5George Mount            }
3984500be62dea3895a98336122a2944cc4ab024bc5George Mount        }
3994500be62dea3895a98336122a2944cc4ab024bc5George Mount    }
4004500be62dea3895a98336122a2944cc4ab024bc5George Mount
401fda5be2466024a656152015c45a7681361d399bbGeorge Mount    public static void setNameOverridesOrdered(final View sceneRoot,
402990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            final ArrayList<View> sharedElementsIn, final Map<String, String> nameOverrides) {
4037d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount        OneShotPreDrawListener.add(sceneRoot, new Runnable() {
4047d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount            @Override
4057d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount            public void run() {
4067d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount                final int numSharedElements = sharedElementsIn.size();
4077d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount                for (int i = 0; i < numSharedElements; i++) {
4087d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount                    View view = sharedElementsIn.get(i);
4097d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount                    String name = view.getTransitionName();
4107d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount                    if (name != null) {
4117d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount                        String inName = findKeyForValue(nameOverrides, name);
4127d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount                        view.setTransitionName(inName);
4130f5ae57910484f1d873fdad90966b6244a633bd4George Mount                    }
4147d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount                }
4157d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount            }
4167d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount        });
4170f5ae57910484f1d873fdad90966b6244a633bd4George Mount    }
4184500be62dea3895a98336122a2944cc4ab024bc5George Mount
419c766ad5a6e0c115f08b933ede22375c7070a3391George Mount    /**
420990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * Utility to find the String key in {@code map} that maps to {@code value}.
421c766ad5a6e0c115f08b933ede22375c7070a3391George Mount     */
422990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    private static String findKeyForValue(Map<String, String> map, String value) {
423990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        for (Map.Entry<String, String> entry : map.entrySet()) {
424990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            if (value.equals(entry.getValue())) {
425990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                return entry.getKey();
426c766ad5a6e0c115f08b933ede22375c7070a3391George Mount            }
427990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        }
428990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        return null;
429990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    }
430990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount
431990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    /**
432990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * After the transition has started, remove all targets that we added to the transitions
433990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * so that the transitions are left in a clean state.
434990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     */
435990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    public static void scheduleRemoveTargets(final Object overallTransitionObj,
436990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            final Object enterTransition, final ArrayList<View> enteringViews,
437990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            final Object exitTransition, final ArrayList<View> exitingViews,
438990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            final Object sharedElementTransition, final ArrayList<View> sharedElementsIn) {
439990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        final Transition overallTransition = (Transition) overallTransitionObj;
440990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        overallTransition.addListener(new Transition.TransitionListener() {
441990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            @Override
442990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            public void onTransitionStart(Transition transition) {
443990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                if (enterTransition != null) {
444990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                    replaceTargets(enterTransition, enteringViews, null);
445990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                }
446990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                if (exitTransition != null) {
447990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                    replaceTargets(exitTransition, exitingViews, null);
448990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                }
449990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                if (sharedElementTransition != null) {
450990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                    replaceTargets(sharedElementTransition, sharedElementsIn, null);
451c766ad5a6e0c115f08b933ede22375c7070a3391George Mount                }
452c766ad5a6e0c115f08b933ede22375c7070a3391George Mount            }
453990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount
454990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            @Override
455990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            public void onTransitionEnd(Transition transition) {
456990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            }
457990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount
458990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            @Override
459990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            public void onTransitionCancel(Transition transition) {
460990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            }
461990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount
462990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            @Override
463990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            public void onTransitionPause(Transition transition) {
464990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            }
465990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount
466990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            @Override
467990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            public void onTransitionResume(Transition transition) {
468990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            }
469990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        });
470990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    }
471990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount
472990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    /**
473990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * Swap the targets for the shared element transition from those Views in sharedElementsOut
474990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * to those in sharedElementsIn
475990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     */
476990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    public static void swapSharedElementTargets(Object sharedElementTransitionObj,
477990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            ArrayList<View> sharedElementsOut, ArrayList<View> sharedElementsIn) {
478990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        TransitionSet sharedElementTransition = (TransitionSet) sharedElementTransitionObj;
479990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        if (sharedElementTransition != null) {
480990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            sharedElementTransition.getTargets().clear();
481990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            sharedElementTransition.getTargets().addAll(sharedElementsIn);
482990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            replaceTargets(sharedElementTransition, sharedElementsOut, sharedElementsIn);
4834500be62dea3895a98336122a2944cc4ab024bc5George Mount        }
4840f5ae57910484f1d873fdad90966b6244a633bd4George Mount    }
4859f4a046cbeb22a24d322a644323b41022ad9d15aGeorge Mount
486990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount
487c766ad5a6e0c115f08b933ede22375c7070a3391George Mount    /**
488990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * This method removes the views from transitions that target ONLY those views and
489990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * replaces them with the new targets list.
490990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * The views list should match those added in addTargets and should contain
491990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * one view that is not in the view hierarchy (state.nonExistentView).
492c766ad5a6e0c115f08b933ede22375c7070a3391George Mount     */
493990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    public static void replaceTargets(Object transitionObj, ArrayList<View> oldTargets,
494990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            ArrayList<View> newTargets) {
495990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        Transition transition = (Transition) transitionObj;
496c766ad5a6e0c115f08b933ede22375c7070a3391George Mount        if (transition instanceof TransitionSet) {
497c766ad5a6e0c115f08b933ede22375c7070a3391George Mount            TransitionSet set = (TransitionSet) transition;
498c766ad5a6e0c115f08b933ede22375c7070a3391George Mount            int numTransitions = set.getTransitionCount();
499c766ad5a6e0c115f08b933ede22375c7070a3391George Mount            for (int i = 0; i < numTransitions; i++) {
500c766ad5a6e0c115f08b933ede22375c7070a3391George Mount                Transition child = set.getTransitionAt(i);
501990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                replaceTargets(child, oldTargets, newTargets);
502c766ad5a6e0c115f08b933ede22375c7070a3391George Mount            }
503c766ad5a6e0c115f08b933ede22375c7070a3391George Mount        } else if (!hasSimpleTarget(transition)) {
504c766ad5a6e0c115f08b933ede22375c7070a3391George Mount            List<View> targets = transition.getTargets();
505990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            if (targets != null && targets.size() == oldTargets.size()
506990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                    && targets.containsAll(oldTargets)) {
507990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                // We have an exact match. We must have added these earlier in addTargets
508990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                final int targetCount = newTargets == null ? 0 : newTargets.size();
509990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                for (int i = 0; i < targetCount; i++) {
510990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                    transition.addTarget(newTargets.get(i));
511990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                }
512990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                for (int i = oldTargets.size() - 1; i >= 0; i--) {
513990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                    transition.removeTarget(oldTargets.get(i));
514c766ad5a6e0c115f08b933ede22375c7070a3391George Mount                }
515c766ad5a6e0c115f08b933ede22375c7070a3391George Mount            }
5169f4a046cbeb22a24d322a644323b41022ad9d15aGeorge Mount        }
5179f4a046cbeb22a24d322a644323b41022ad9d15aGeorge Mount    }
5189f4a046cbeb22a24d322a644323b41022ad9d15aGeorge Mount
519990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    /**
520990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * Adds a View target to a transition. If transitionObj is null, nothing is done.
521990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     */
522990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    public static void addTarget(Object transitionObj, View view) {
523990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        if (transitionObj != null) {
524990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            Transition transition = (Transition) transitionObj;
525990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            transition.addTarget(view);
526990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        }
527c766ad5a6e0c115f08b933ede22375c7070a3391George Mount    }
528c766ad5a6e0c115f08b933ede22375c7070a3391George Mount
529990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    /**
530990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * Remove a View target to a transition. If transitionObj is null, nothing is done.
531990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     */
532990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    public static void removeTarget(Object transitionObj, View view) {
533990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        if (transitionObj != null) {
534990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            Transition transition = (Transition) transitionObj;
535990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            transition.removeTarget(view);
536990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        }
537c766ad5a6e0c115f08b933ede22375c7070a3391George Mount    }
538c766ad5a6e0c115f08b933ede22375c7070a3391George Mount
539990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    /**
540990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * Sets the epicenter of a transition to a rect object. The object can be modified until
541990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     * the transition runs.
542990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount     */
543990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    public static void setEpicenter(Object transitionObj, final Rect epicenter) {
544990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        if (transitionObj != null) {
545990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            Transition transition = (Transition) transitionObj;
546990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            transition.setEpicenterCallback(new Transition.EpicenterCallback() {
547990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                @Override
548990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                public Rect onGetEpicenter(Transition transition) {
549990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                    if (epicenter == null || epicenter.isEmpty()) {
550990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                        return null;
551990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                    }
552990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                    return epicenter;
553990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount                }
554990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            });
555990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount        }
5569f4a046cbeb22a24d322a644323b41022ad9d15aGeorge Mount    }
5579f4a046cbeb22a24d322a644323b41022ad9d15aGeorge Mount
558990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount    public static void scheduleNameReset(final ViewGroup sceneRoot,
559990e6fc0326f5948736650c0cb71b6002d443c9cGeorge Mount            final ArrayList<View> sharedElementsIn, final Map<String, String> nameOverrides) {
5607d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount        OneShotPreDrawListener.add(sceneRoot, new Runnable() {
5617d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount            @Override
5627d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount            public void run() {
5637d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount                final int numSharedElements = sharedElementsIn.size();
5647d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount                for (int i = 0; i < numSharedElements; i++) {
5657d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount                    final View view = sharedElementsIn.get(i);
5667d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount                    final String name = view.getTransitionName();
5677d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount                    final String inName = nameOverrides.get(name);
5687d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount                    view.setTransitionName(inName);
5697d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount                }
5707d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount            }
5717d542b74cbd4d5c68193e230fa4af96cecfc7dbbGeorge Mount        });
5729f4a046cbeb22a24d322a644323b41022ad9d15aGeorge Mount    }
5734500be62dea3895a98336122a2944cc4ab024bc5George Mount}
574