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

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

Fix animation and layoutTransition issues.

There were some subtle timing issues in animators with ending animations that
were not completely initialized (possibly because a startDelay'd animator
was ended before the delay elapsed).
Also, LayoutTransition had bugs around running a transition on a container
while a previously-started transition was still in progress. This could result
in some minor artifacts or crash bugs, depending on the durations and delays set
on the transition animations.

Change-Id: Ic6a69601f1ce9a55db15fff6b8ed25950b354491
parent 5ed9a805
Loading
Loading
Loading
Loading
+29 −7
Original line number Original line Diff line number Diff line
@@ -617,7 +617,6 @@ public class LayoutTransition {
                        Animator prevAnimation = currentChangingAnimations.get(child);
                        Animator prevAnimation = currentChangingAnimations.get(child);
                        if (prevAnimation != null) {
                        if (prevAnimation != null) {
                            prevAnimation.cancel();
                            prevAnimation.cancel();
                            currentChangingAnimations.remove(child);
                        }
                        }
                        Animator pendingAnimation = pendingAnimations.get(child);
                        Animator pendingAnimation = pendingAnimations.get(child);
                        if (pendingAnimation != null) {
                        if (pendingAnimation != null) {
@@ -639,7 +638,6 @@ public class LayoutTransition {
                };
                };
                // Remove the animation from the cache when it ends
                // Remove the animation from the cache when it ends
                anim.addListener(new AnimatorListenerAdapter() {
                anim.addListener(new AnimatorListenerAdapter() {
                    private boolean canceled = false;


                    @Override
                    @Override
                    public void onAnimationStart(Animator animator) {
                    public void onAnimationStart(Animator animator) {
@@ -654,17 +652,13 @@ public class LayoutTransition {


                    @Override
                    @Override
                    public void onAnimationCancel(Animator animator) {
                    public void onAnimationCancel(Animator animator) {
                        // we remove canceled animations immediately, not here
                        canceled = true;
                        child.removeOnLayoutChangeListener(listener);
                        child.removeOnLayoutChangeListener(listener);
                        layoutChangeListenerMap.remove(child);
                        layoutChangeListenerMap.remove(child);
                    }
                    }


                    @Override
                    @Override
                    public void onAnimationEnd(Animator animator) {
                    public void onAnimationEnd(Animator animator) {
                        if (!canceled) {
                        currentChangingAnimations.remove(child);
                        currentChangingAnimations.remove(child);
                        }
                        if (mListeners != null) {
                        if (mListeners != null) {
                            for (TransitionListener listener : mListeners) {
                            for (TransitionListener listener : mListeners) {
                                listener.endTransition(LayoutTransition.this, parent, child,
                                listener.endTransition(LayoutTransition.this, parent, child,
@@ -718,6 +712,28 @@ public class LayoutTransition {
        return (currentChangingAnimations.size() > 0 || currentVisibilityAnimations.size() > 0);
        return (currentChangingAnimations.size() > 0 || currentVisibilityAnimations.size() > 0);
    }
    }


    /**
     * Cancels the currently running transition. Note that we cancel() the changing animations
     * but end() the visibility animations. This is because this method is currently called
     * in the context of starting a new transition, so we want to move things from their mid-
     * transition positions, but we want them to have their end-transition visibility.
     *
     * @hide
     */
    public void cancel() {
        HashMap<View, Animator> currentAnimCopy =
                (HashMap<View, Animator>) currentChangingAnimations.clone();
        for (Animator anim : currentAnimCopy.values()) {
            anim.cancel();
        }
        currentChangingAnimations.clear();
        currentAnimCopy = (HashMap<View, Animator>) currentVisibilityAnimations.clone();
        for (Animator anim : currentAnimCopy.values()) {
            anim.end();
        }
        currentVisibilityAnimations.clear();
    }

    /**
    /**
     * This method runs the animation that makes an added item appear.
     * This method runs the animation that makes an added item appear.
     *
     *
@@ -810,6 +826,9 @@ public class LayoutTransition {
     * @param child The View being added to the ViewGroup.
     * @param child The View being added to the ViewGroup.
     */
     */
    public void addChild(ViewGroup parent, View child) {
    public void addChild(ViewGroup parent, View child) {
        if (isRunning()) {
            cancel();
        }
        if (mListeners != null) {
        if (mListeners != null) {
            for (TransitionListener listener : mListeners) {
            for (TransitionListener listener : mListeners) {
                listener.startTransition(this, parent, child, APPEARING);
                listener.startTransition(this, parent, child, APPEARING);
@@ -842,6 +861,9 @@ public class LayoutTransition {
     * @param child The View being removed from the ViewGroup.
     * @param child The View being removed from the ViewGroup.
     */
     */
    public void removeChild(ViewGroup parent, View child) {
    public void removeChild(ViewGroup parent, View child) {
        if (isRunning()) {
            cancel();
        }
        if (mListeners != null) {
        if (mListeners != null) {
            for (TransitionListener listener : mListeners) {
            for (TransitionListener listener : mListeners) {
                listener.startTransition(this, parent, child, DISAPPEARING);
                listener.startTransition(this, parent, child, DISAPPEARING);
+9 −6
Original line number Original line Diff line number Diff line
@@ -895,7 +895,14 @@ public class ValueAnimator extends Animator {
            throw new AndroidRuntimeException("Animators may only be run on Looper threads");
            throw new AndroidRuntimeException("Animators may only be run on Looper threads");
        }
        }
        mPlayingBackwards = playBackwards;
        mPlayingBackwards = playBackwards;
        mCurrentIteration = 0;
        mPlayingState = STOPPED;
        mStartedDelay = false;
        sPendingAnimations.get().add(this);
        if (mStartDelay == 0) {
        if (mStartDelay == 0) {
            // This sets the initial value of the animation, prior to actually starting it running
            setCurrentPlayTime(getCurrentPlayTime());

            if (mListeners != null) {
            if (mListeners != null) {
                ArrayList<AnimatorListener> tmpListeners =
                ArrayList<AnimatorListener> tmpListeners =
                        (ArrayList<AnimatorListener>) mListeners.clone();
                        (ArrayList<AnimatorListener>) mListeners.clone();
@@ -904,13 +911,7 @@ public class ValueAnimator extends Animator {
                    tmpListeners.get(i).onAnimationStart(this);
                    tmpListeners.get(i).onAnimationStart(this);
                }
                }
            }
            }
            // This sets the initial value of the animation, prior to actually starting it running
            setCurrentPlayTime(getCurrentPlayTime());
        }
        }
        mCurrentIteration = 0;
        mPlayingState = STOPPED;
        mStartedDelay = false;
        sPendingAnimations.get().add(this);
        AnimationHandler animationHandler = sAnimationHandler.get();
        AnimationHandler animationHandler = sAnimationHandler.get();
        if (animationHandler == null) {
        if (animationHandler == null) {
            animationHandler = new AnimationHandler();
            animationHandler = new AnimationHandler();
@@ -947,6 +948,8 @@ public class ValueAnimator extends Animator {
            // Special case if the animation has not yet started; get it ready for ending
            // Special case if the animation has not yet started; get it ready for ending
            mStartedDelay = false;
            mStartedDelay = false;
            startAnimation();
            startAnimation();
        } else if (!mInitialized) {
            initAnimation();
        }
        }
        // The final value set on the target varies, depending on whether the animation
        // The final value set on the target varies, depending on whether the animation
        // was supposed to repeat an odd number of times
        // was supposed to repeat an odd number of times
+4 −0
Original line number Original line Diff line number Diff line
@@ -2938,6 +2938,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    private void addViewInner(View child, int index, LayoutParams params,
    private void addViewInner(View child, int index, LayoutParams params,
            boolean preventRequestLayout) {
            boolean preventRequestLayout) {


        if (mTransition != null && mTransition.isRunning()) {
            mTransition.cancel();
        }

        if (child.getParent() != null) {
        if (child.getParent() != null) {
            throw new IllegalStateException("The specified child already has a parent. " +
            throw new IllegalStateException("The specified child already has a parent. " +
                    "You must call removeView() on the child's parent first.");
                    "You must call removeView() on the child's parent first.");