Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8af78483 authored by George Mount's avatar George Mount Committed by Android (Google) Code Review
Browse files

Merge "Limit shared element transition to shared elements and children." into mnc-dev

parents 0021d3fa c855f7d0
Loading
Loading
Loading
Loading
+83 −19
Original line number Diff line number Diff line
@@ -28,7 +28,6 @@ import android.transition.TransitionSet;
import android.util.ArrayMap;
import android.util.Log;
import android.util.LogWriter;
import android.util.Pair;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
@@ -1005,13 +1004,20 @@ final class BackStackRecord extends FragmentTransaction implements
                outFragment.getExitTransition());
    }

    private static Transition getSharedElementTransition(Fragment inFragment, Fragment outFragment,
            boolean isBack) {
    private static TransitionSet getSharedElementTransition(Fragment inFragment,
            Fragment outFragment, boolean isBack) {
        if (inFragment == null || outFragment == null) {
            return null;
        }
        return cloneTransition(isBack ? outFragment.getSharedElementReturnTransition() :
                inFragment.getSharedElementEnterTransition());
        Transition transition = cloneTransition(isBack
                ? outFragment.getSharedElementReturnTransition()
                : inFragment.getSharedElementEnterTransition());
        if (transition == null) {
            return null;
        }
        TransitionSet transitionSet = new TransitionSet();
        transitionSet.addTransition(transition);
        return transitionSet;
    }

    private static ArrayList<View> captureExitingViews(Transition exitTransition,
@@ -1070,7 +1076,7 @@ final class BackStackRecord extends FragmentTransaction implements
     * capturing the final state of the Transition.</p>
     */
    private ArrayList<View> addTransitionTargets(final TransitionState state,
            final Transition enterTransition, final Transition sharedElementTransition,
            final Transition enterTransition, final TransitionSet sharedElementTransition,
            final Transition overallTransition, final View container,
            final Fragment inFragment, final Fragment outFragment,
            final ArrayList<View> hiddenFragmentViews, final boolean isBack,
@@ -1094,11 +1100,8 @@ final class BackStackRecord extends FragmentTransaction implements
                        if (sharedElementTransition != null) {
                            namedViews = mapSharedElementsIn(state, isBack, inFragment);
                            removeTargets(sharedElementTransition, sharedElementTargets);
                            sharedElementTargets.clear();
                            sharedElementTargets.add(state.nonExistentView);
                            sharedElementTargets.addAll(namedViews.values());

                            addTargets(sharedElementTransition, sharedElementTargets);
                            setSharedElementTargets(sharedElementTransition,
                                    state.nonExistentView, namedViews, sharedElementTargets);

                            setEpicenterIn(namedViews, state);

@@ -1241,8 +1244,8 @@ final class BackStackRecord extends FragmentTransaction implements
            Fragment outFragment = firstOutFragments.get(containerId);

            Transition enterTransition = getEnterTransition(inFragment, isBack);
            Transition sharedElementTransition = getSharedElementTransition(inFragment, outFragment,
                    isBack);
            TransitionSet sharedElementTransition =
                    getSharedElementTransition(inFragment, outFragment, isBack);
            Transition exitTransition = getExitTransition(outFragment, isBack);

            if (enterTransition == null && sharedElementTransition == null &&
@@ -1256,9 +1259,8 @@ final class BackStackRecord extends FragmentTransaction implements
            ArrayList<View> sharedElementTargets = new ArrayList<View>();
            if (sharedElementTransition != null) {
                namedViews = remapSharedElements(state, outFragment, isBack);
                sharedElementTargets.add(state.nonExistentView);
                sharedElementTargets.addAll(namedViews.values());
                addTargets(sharedElementTransition, sharedElementTargets);
                setSharedElementTargets(sharedElementTransition,
                        state.nonExistentView, namedViews, sharedElementTargets);

                // Notify the start of the transition.
                SharedElementCallback callback = isBack ?
@@ -1294,8 +1296,8 @@ final class BackStackRecord extends FragmentTransaction implements
            if (transition != null) {
                ArrayList<View> hiddenFragments = new ArrayList<View>();
                ArrayList<View> enteringViews = addTransitionTargets(state, enterTransition,
                        sharedElementTransition, transition, sceneRoot, inFragment, outFragment,
                        hiddenFragments, isBack, sharedElementTargets);
                        sharedElementTransition, transition, sceneRoot, inFragment,
                        outFragment, hiddenFragments, isBack, sharedElementTargets);

                transition.setNameOverrides(state.nameOverrides);
                // We want to exclude hidden views later, so we need a non-null list in the
@@ -1307,9 +1309,71 @@ final class BackStackRecord extends FragmentTransaction implements
                // Remove the view targeting after the transition starts
                removeTargetedViewsFromTransitions(sceneRoot, state.nonExistentView,
                        enterTransition, enteringViews, exitTransition, exitingViews,
                        sharedElementTransition, sharedElementTargets, transition, hiddenFragments);
                        sharedElementTransition, sharedElementTargets, transition,
                        hiddenFragments);
            }
        }
    }

    /**
     * Finds all children of the shared elements and sets the wrapping TransitionSet
     * targets to point to those. It also limits transitions that have no targets to the
     * specific shared elements. This allows developers to target child views of the
     * shared elements specifically, but this doesn't happen by default.
     */
    private static void setSharedElementTargets(TransitionSet transition,
            View nonExistentView, ArrayMap<String, View> namedViews,
            ArrayList<View> sharedElementTargets) {
        sharedElementTargets.clear();
        sharedElementTargets.addAll(namedViews.values());

        final List<View> views = transition.getTargets();
        views.clear();
        final int count = sharedElementTargets.size();
        for (int i = 0; i < count; i++) {
            final View view = sharedElementTargets.get(i);
            bfsAddViewChildren(views, view);
        }
        sharedElementTargets.add(nonExistentView);
        addTargets(transition, sharedElementTargets);
    }

    /**
     * Uses a breadth-first scheme to add startView and all of its children to views.
     * It won't add a child if it is already in views.
     */
    private static void bfsAddViewChildren(final List<View> views, final View startView) {
        final int startIndex = views.size();
        if (containedBeforeIndex(views, startView, startIndex)) {
            return; // This child is already in the list, so all its children are also.
        }
        views.add(startView);
        for (int index = startIndex; index < views.size(); index++) {
            final View view = views.get(index);
            if (view instanceof ViewGroup) {
                ViewGroup viewGroup = (ViewGroup) view;
                final int childCount =  viewGroup.getChildCount();
                for (int childIndex = 0; childIndex < childCount; childIndex++) {
                    final View child = viewGroup.getChildAt(childIndex);
                    if (!containedBeforeIndex(views, child, startIndex)) {
                        views.add(child);
                    }
                }
            }
        }
    }

    /**
     * Does a linear search through views for view, limited to maxIndex.
     */
    private static boolean containedBeforeIndex(final List<View> views, final View view,
            final int maxIndex) {
        for (int i = 0; i < maxIndex; i++) {
            if (views.get(i) == view) {
                return true;
            }
        }
        return false;
    }

    /**