13f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki/* 2ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * Copyright 2018 The Android Open Source Project 33f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * 43f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * Licensed under the Apache License, Version 2.0 (the "License"); 53f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * you may not use this file except in compliance with the License. 63f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * You may obtain a copy of the License at 73f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * 83f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * http://www.apache.org/licenses/LICENSE-2.0 93f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * 103f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * Unless required by applicable law or agreed to in writing, software 113f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * distributed under the License is distributed on an "AS IS" BASIS, 123f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * See the License for the specific language governing permissions and 143f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * limitations under the License. 153f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 163f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.fragment.app; 183f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 19ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP; 203f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 213f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Arakiimport android.graphics.Rect; 22320113721c2e14bbc2403809046fa2959a665c11Aurimas Liutikasimport android.view.View; 23320113721c2e14bbc2403809046fa2959a665c11Aurimas Liutikasimport android.view.ViewGroup; 24320113721c2e14bbc2403809046fa2959a665c11Aurimas Liutikas 25ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.RestrictTo; 26ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.core.view.ViewCompat; 27ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.core.view.ViewGroupCompat; 283f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 293f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Arakiimport java.util.ArrayList; 303f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Arakiimport java.util.List; 313f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Arakiimport java.util.Map; 323f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 333f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 343f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki/** 353f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * @hide 363f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 373f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki@RestrictTo(LIBRARY_GROUP) 383f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Arakipublic abstract class FragmentTransitionImpl { 393f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 403f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki /** 413f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * Returns {@code true} if this implementation can handle the specified {@link transition}. 423f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 433f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki public abstract boolean canHandle(Object transition); 443f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 453f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki /** 463f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * Returns a clone of a transition or null if it is null 473f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 483f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki public abstract Object cloneTransition(Object transition); 493f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 503f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki /** 513f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * Wraps a transition in a TransitionSet and returns the set. If transition is null, null is 523f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * returned. 533f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 543f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki public abstract Object wrapTransitionInSet(Object transition); 553f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 563f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki /** 573f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * Finds all children of the shared elements and sets the wrapping TransitionSet 583f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * targets to point to those. It also limits transitions that have no targets to the 593f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * specific shared elements. This allows developers to target child views of the 603f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * shared elements specifically, but this doesn't happen by default. 613f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 623f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki public abstract void setSharedElementTargets(Object transitionObj, 633f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki View nonExistentView, ArrayList<View> sharedViews); 643f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 653f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki /** 663f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * Sets a transition epicenter to the rectangle of a given View. 673f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 683f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki public abstract void setEpicenter(Object transitionObj, View view); 693f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 703f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki /** 713f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * Replacement for view.getBoundsOnScreen because that is not public. This returns a rect 723f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * containing the bounds relative to the screen that the view is in. 733f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 743f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki protected void getBoundsOnScreen(View view, Rect epicenter) { 753f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki int[] loc = new int[2]; 763f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki view.getLocationOnScreen(loc); 773f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki epicenter.set(loc[0], loc[1], loc[0] + view.getWidth(), loc[1] + view.getHeight()); 783f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 793f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 803f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki /** 813f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * This method adds views as targets to the transition, but only if the transition 823f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * doesn't already have a target. It is best for views to contain one View object 833f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * that does not exist in the view hierarchy (state.nonExistentView) so that 843f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * when they are removed later, a list match will suffice to remove the targets. 853f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * Otherwise, if you happened to have targeted the exact views for the transition, 863f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * the replaceTargets call will remove them unexpectedly. 873f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 883f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki public abstract void addTargets(Object transitionObj, ArrayList<View> views); 893f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 903f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki /** 913f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * Creates a TransitionSet that plays all passed transitions together. Any null 923f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * transitions passed will not be added to the set. If all are null, then an empty 933f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * TransitionSet will be returned. 943f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 953f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki public abstract Object mergeTransitionsTogether(Object transition1, Object transition2, 963f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki Object transition3); 973f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 983f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki /** 993f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * After the transition completes, the fragment's view is set to GONE and the exiting 1003f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * views are set to VISIBLE. 1013f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 1023f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki public abstract void scheduleHideFragmentView(Object exitTransitionObj, View fragmentView, 1033f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki ArrayList<View> exitingViews); 1043f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 1053f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki /** 1063f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * Combines enter, exit, and shared element transition so that they play in the proper 1073f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * sequence. First the exit transition plays along with the shared element transition. 1083f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * When the exit transition completes, the enter transition starts. The shared element 1093f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * transition can continue running while the enter transition plays. 1103f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * 1113f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * @return A TransitionSet with all of enter, exit, and shared element transitions in 1123f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * it (modulo null values), ordered such that they play in the proper sequence. 1133f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 1143f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki public abstract Object mergeTransitionsInSequence(Object exitTransitionObj, 1153f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki Object enterTransitionObj, Object sharedElementTransitionObj); 1163f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 1173f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki /** 1183f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * Calls {@code TransitionManager#beginDelayedTransition(ViewGroup, Transition)}. 1193f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 1203f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki public abstract void beginDelayedTransition(ViewGroup sceneRoot, Object transition); 1213f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 1223f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki /** 1233f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * Prepares for setting the shared element names by gathering the names of the incoming 1243f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * shared elements and clearing them. {@link #setNameOverridesReordered(View, ArrayList, 1253f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * ArrayList, ArrayList, Map)} must be called after this to complete setting the shared element 1263f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * name overrides. This must be called before 1273f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * {@link #beginDelayedTransition(ViewGroup, Object)}. 1283f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 1293f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki ArrayList<String> prepareSetNameOverridesReordered(ArrayList<View> sharedElementsIn) { 1303f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki final ArrayList<String> names = new ArrayList<>(); 1313f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki final int numSharedElements = sharedElementsIn.size(); 1323f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki for (int i = 0; i < numSharedElements; i++) { 1333f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki final View view = sharedElementsIn.get(i); 1343f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki names.add(ViewCompat.getTransitionName(view)); 1353f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki ViewCompat.setTransitionName(view, null); 1363f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 1373f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki return names; 1383f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 1393f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 1403f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki /** 1413f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * Changes the shared element names for the incoming shared elements to match those of the 1423f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * outgoing shared elements. This also temporarily clears the shared element names of the 1433f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * outgoing shared elements. Must be called after 1443f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * {@link #beginDelayedTransition(ViewGroup, Object)}. 1453f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 1463f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki void setNameOverridesReordered(final View sceneRoot, 1473f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki final ArrayList<View> sharedElementsOut, final ArrayList<View> sharedElementsIn, 1483f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki final ArrayList<String> inNames, final Map<String, String> nameOverrides) { 1493f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki final int numSharedElements = sharedElementsIn.size(); 1503f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki final ArrayList<String> outNames = new ArrayList<>(); 1513f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 1523f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki for (int i = 0; i < numSharedElements; i++) { 1533f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki final View view = sharedElementsOut.get(i); 1543f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki final String name = ViewCompat.getTransitionName(view); 1553f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki outNames.add(name); 1563f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki if (name == null) { 1573f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki continue; 1583f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 1593f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki ViewCompat.setTransitionName(view, null); 1603f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki final String inName = nameOverrides.get(name); 1613f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki for (int j = 0; j < numSharedElements; j++) { 1623f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki if (inName.equals(inNames.get(j))) { 1633f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki ViewCompat.setTransitionName(sharedElementsIn.get(j), name); 1643f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki break; 1653f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 1663f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 1673f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 1683f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 1693f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki OneShotPreDrawListener.add(sceneRoot, new Runnable() { 1703f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki @Override 1713f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki public void run() { 1723f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki for (int i = 0; i < numSharedElements; i++) { 1733f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki ViewCompat.setTransitionName(sharedElementsIn.get(i), inNames.get(i)); 1743f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki ViewCompat.setTransitionName(sharedElementsOut.get(i), outNames.get(i)); 1753f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 1763f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 1773f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki }); 1783f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 1793f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 1803f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki /** 1813f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions. 1823f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * 1833f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and 1843f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * a normal View or a ViewGroup with 1853f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * {@link android.view.ViewGroup#isTransitionGroup()} true. 1863f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * @param view The base of the view hierarchy to look in. 1873f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 1883f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki void captureTransitioningViews(ArrayList<View> transitioningViews, View view) { 1893f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki if (view.getVisibility() == View.VISIBLE) { 1903f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki if (view instanceof ViewGroup) { 1913f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki ViewGroup viewGroup = (ViewGroup) view; 1923f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki if (ViewGroupCompat.isTransitionGroup(viewGroup)) { 1933f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki transitioningViews.add(viewGroup); 1943f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } else { 1953f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki int count = viewGroup.getChildCount(); 1963f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki for (int i = 0; i < count; i++) { 1973f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki View child = viewGroup.getChildAt(i); 1983f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki captureTransitioningViews(transitioningViews, child); 1993f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 2003f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 2013f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } else { 2023f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki transitioningViews.add(view); 2033f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 2043f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 2053f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 2063f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 2073f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki /** 2083f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * Finds all views that have transition names in the hierarchy under the given view and 2093f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * stores them in {@code namedViews} map with the name as the key. 2103f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 2113f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki void findNamedViews(Map<String, View> namedViews, View view) { 2123f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki if (view.getVisibility() == View.VISIBLE) { 2133f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki String transitionName = ViewCompat.getTransitionName(view); 2143f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki if (transitionName != null) { 2153f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki namedViews.put(transitionName, view); 2163f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 2173f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki if (view instanceof ViewGroup) { 2183f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki ViewGroup viewGroup = (ViewGroup) view; 2193f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki int count = viewGroup.getChildCount(); 2203f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki for (int i = 0; i < count; i++) { 2213f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki View child = viewGroup.getChildAt(i); 2223f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki findNamedViews(namedViews, child); 2233f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 2243f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 2253f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 2263f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 2273f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 2283f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki /** 2293f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki *Applies the prepared {@code nameOverrides} to the view hierarchy. 2303f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 2313f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki void setNameOverridesOrdered(final View sceneRoot, 2323f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki final ArrayList<View> sharedElementsIn, final Map<String, String> nameOverrides) { 2333f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki OneShotPreDrawListener.add(sceneRoot, new Runnable() { 2343f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki @Override 2353f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki public void run() { 2363f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki final int numSharedElements = sharedElementsIn.size(); 2373f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki for (int i = 0; i < numSharedElements; i++) { 2383f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki View view = sharedElementsIn.get(i); 2393f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki String name = ViewCompat.getTransitionName(view); 2403f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki if (name != null) { 2413f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki String inName = findKeyForValue(nameOverrides, name); 2423f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki ViewCompat.setTransitionName(view, inName); 2433f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 2443f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 2453f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 2463f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki }); 2473f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 2483f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 2493f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki /** 2503f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * After the transition has started, remove all targets that we added to the transitions 2513f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * so that the transitions are left in a clean state. 2523f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 2533f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki public abstract void scheduleRemoveTargets(Object overallTransitionObj, 2543f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki Object enterTransition, ArrayList<View> enteringViews, 2553f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki Object exitTransition, ArrayList<View> exitingViews, 2563f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki Object sharedElementTransition, ArrayList<View> sharedElementsIn); 2573f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 2583f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki /** 2593f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * Swap the targets for the shared element transition from those Views in sharedElementsOut 2603f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * to those in sharedElementsIn 2613f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 2623f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki public abstract void swapSharedElementTargets(Object sharedElementTransitionObj, 2633f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki ArrayList<View> sharedElementsOut, ArrayList<View> sharedElementsIn); 2643f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 2653f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki /** 2663f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * This method removes the views from transitions that target ONLY those views and 2673f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * replaces them with the new targets list. 2683f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * The views list should match those added in addTargets and should contain 2693f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * one view that is not in the view hierarchy (state.nonExistentView). 2703f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 2713f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki public abstract void replaceTargets(Object transitionObj, ArrayList<View> oldTargets, 2723f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki ArrayList<View> newTargets); 2733f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 2743f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki /** 2753f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * Adds a View target to a transition. If transitionObj is null, nothing is done. 2763f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 2773f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki public abstract void addTarget(Object transitionObj, View view); 2783f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 2793f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki /** 2803f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * Remove a View target to a transition. If transitionObj is null, nothing is done. 2813f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 2823f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki public abstract void removeTarget(Object transitionObj, View view); 2833f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 2843f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki /** 2853f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * Sets the epicenter of a transition to a rect object. The object can be modified until 2863f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * the transition runs. 2873f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 2883f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki public abstract void setEpicenter(Object transitionObj, Rect epicenter); 2893f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 2903f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki void scheduleNameReset(final ViewGroup sceneRoot, 2913f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki final ArrayList<View> sharedElementsIn, final Map<String, String> nameOverrides) { 2923f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki OneShotPreDrawListener.add(sceneRoot, new Runnable() { 2933f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki @Override 2943f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki public void run() { 2953f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki final int numSharedElements = sharedElementsIn.size(); 2963f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki for (int i = 0; i < numSharedElements; i++) { 2973f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki final View view = sharedElementsIn.get(i); 2983f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki final String name = ViewCompat.getTransitionName(view); 2993f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki final String inName = nameOverrides.get(name); 3003f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki ViewCompat.setTransitionName(view, inName); 3013f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 3023f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 3033f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki }); 3043f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 3053f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 3063f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki /** 3073f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * Uses a breadth-first scheme to add startView and all of its children to views. 3083f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * It won't add a child if it is already in views. 3093f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 3103f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki protected static void bfsAddViewChildren(final List<View> views, final View startView) { 3113f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki final int startIndex = views.size(); 3123f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki if (containedBeforeIndex(views, startView, startIndex)) { 3133f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki return; // This child is already in the list, so all its children are also. 3143f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 3153f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki views.add(startView); 3163f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki for (int index = startIndex; index < views.size(); index++) { 3173f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki final View view = views.get(index); 3183f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki if (view instanceof ViewGroup) { 3193f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki ViewGroup viewGroup = (ViewGroup) view; 3203f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki final int childCount = viewGroup.getChildCount(); 3213f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki for (int childIndex = 0; childIndex < childCount; childIndex++) { 3223f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki final View child = viewGroup.getChildAt(childIndex); 3233f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki if (!containedBeforeIndex(views, child, startIndex)) { 3243f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki views.add(child); 3253f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 3263f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 3273f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 3283f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 3293f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 3303f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 3313f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki /** 3323f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * Does a linear search through views for view, limited to maxIndex. 3333f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 3343f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki private static boolean containedBeforeIndex(final List<View> views, final View view, 3353f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki final int maxIndex) { 3363f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki for (int i = 0; i < maxIndex; i++) { 3373f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki if (views.get(i) == view) { 3383f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki return true; 3393f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 3403f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 3413f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki return false; 3423f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 3433f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 3443f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki /** 3453f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * Simple utility to detect if a list is null or has no elements. 3463f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 3473f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki protected static boolean isNullOrEmpty(List list) { 3483f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki return list == null || list.isEmpty(); 3493f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 3503f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 3513f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki /** 3523f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki * Utility to find the String key in {@code map} that maps to {@code value}. 3533f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki */ 3543f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki @SuppressWarnings("WeakerAccess") 3553f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki static String findKeyForValue(Map<String, String> map, String value) { 3563f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki for (Map.Entry<String, String> entry : map.entrySet()) { 3573f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki if (value.equals(entry.getValue())) { 3583f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki return entry.getKey(); 3593f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 3603f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 3613f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki return null; 3623f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki } 3633f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki 3643f82583302c46d84017633ce93ef8c7b3278eb5eYuichi Araki} 365