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

Commit e9d32ea1 authored by Chet Haase's avatar Chet Haase
Browse files

Starting new transition cancels running transition

The behavior of running a transition is janky and unpredictable,
when there is already a transition running on the same scene root.
Usually, the new transition simply jumps to the end values, or
jumps to the start values for that transition and animates from
there.

A better approach is to cancel any running transition first, the
start the new transition from that point.

Even better would be to blend old/new transitions, or at least adjust
the animation timing according to where/when the previous transition
stopped. In the meantime, this fix is at least better than the
previous approach of ignoring running transitions.

Change-Id: I4f5fabb55f6454f1e9d66589a9a7c36f9fc013fb
parent 90b89944
Loading
Loading
Loading
Loading
+28 −6
Original line number Diff line number Diff line
@@ -78,6 +78,10 @@ public abstract class Transition {
    private ArrayList<TransitionValues> mPlayStartValuesList = new ArrayList<TransitionValues>();
    private ArrayList<TransitionValues> mPlayEndValuesList = new ArrayList<TransitionValues>();

    // Track all animators in use in case the transition gets canceled and needs to
    // cancel running animators
    private ArrayList<Animator> mCurrentAnimators = new ArrayList<Animator>();

    // Number of per-target instances of this Transition currently running. This count is
    // determined by calls to startTransition() and endTransition()
    int mNumInstances = 0;
@@ -401,13 +405,30 @@ public abstract class Transition {
            TransitionValues start = mPlayStartValuesList.get(i);
            TransitionValues end = mPlayEndValuesList.get(i);
            startTransition();
            animate(play(sceneRoot, start, end));
            runAnimator(play(sceneRoot, start, end));
        }
        mPlayStartValuesList.clear();
        mPlayEndValuesList.clear();
        endTransition();
    }

    private void runAnimator(Animator animator) {
        if (animator != null) {
            // TODO: could be a single listener instance for all of them since it uses the param
            animator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationStart(Animator animation) {
                    mCurrentAnimators.add(animation);
                }
                @Override
                public void onAnimationEnd(Animator animation) {
                    mCurrentAnimators.remove(animation);
                }
            });
            animate(animator);
        }
    }

    /**
     * Captures the current scene of values for the properties that this
     * transition monitors. These values can be either the start or end
@@ -667,11 +688,6 @@ public abstract class Transition {
                animator.setInterpolator(getInterpolator());
            }
            animator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationCancel(Animator animation) {
                    cancelTransition();
                }

                @Override
                public void onAnimationEnd(Animator animation) {
                    endTransition();
@@ -771,6 +787,7 @@ public abstract class Transition {
            mEndValues.clear();
            mEndIdValues.clear();
            mEndItemIdValues.clear();
            mCurrentAnimators.clear();
        }
    }

@@ -781,6 +798,11 @@ public abstract class Transition {
    protected void cancelTransition() {
        // TODO: how does this work with instances?
        // TODO: this doesn't actually do *anything* yet
        int numAnimators = mCurrentAnimators.size();
        for (int i = 0; i < numAnimators; ++i) {
            Animator animator = mCurrentAnimators.get(i);
            animator.cancel();
        }
        onTransitionCancel();
        if (mListeners != null && mListeners.size() > 0) {
            ArrayList<TransitionListener> tmpListeners =
+9 −0
Original line number Diff line number Diff line
@@ -302,6 +302,15 @@ public class TransitionGroup extends Transition {
        }
    }

    @Override
    protected void cancelTransition() {
        super.cancelTransition();
        int numTransitions = mTransitions.size();
        for (int i = 0; i < numTransitions; ++i) {
            mTransitions.get(i).cancelTransition();
        }
    }

    @Override
    String toString(String indent) {
        String result = super.toString(indent);
+16 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */
package android.view.transition;

import android.util.ArrayMap;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;

@@ -40,6 +41,8 @@ public class TransitionManager {
    HashMap<Scene, Transition> mSceneTransitions = new HashMap<Scene, Transition>();
    HashMap<Scene, HashMap<Scene, Transition>> mScenePairTransitions =
            new HashMap<Scene, HashMap<Scene, Transition>>();
    static ArrayMap<ViewGroup, Transition> sRunningTransitions =
            new ArrayMap<ViewGroup, Transition>();

        /**
     * Sets the transition to be used for any scene change for which no
@@ -141,6 +144,11 @@ public class TransitionManager {

        final ViewGroup sceneRoot = scene.getSceneRoot();

        Transition runningTransition = sRunningTransitions.get(sceneRoot);
        if (runningTransition != null) {
            runningTransition.cancelTransition();
        }

        // Capture current values
        if (transition != null) {
            transition.captureValues(sceneRoot, true);
@@ -159,6 +167,14 @@ public class TransitionManager {
            observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                public boolean onPreDraw() {
                    sceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
                    // Add to running list, handle end to remove it
                    sRunningTransitions.put(sceneRoot, transition);
                    transition.addListener(new Transition.TransitionListenerAdapter() {
                        @Override
                        public void onTransitionEnd(Transition transition) {
                            sRunningTransitions.remove(sceneRoot);
                        }
                    });
                    transition.captureValues(sceneRoot, false);
                    transition.play(sceneRoot);
                    return true;