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

Commit 632142dc authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge changes from topic "cherrypicker-L06600000959260644:N82800001349763665"...

Merge changes from topic "cherrypicker-L06600000959260644:N82800001349763665" into udc-dev am: 05ee5fc9

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/22144003



Change-Id: I7443303656698df1d4bbcf1ce68c672d4ef5048c
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 8c3ecc94 05ee5fc9
Loading
Loading
Loading
Loading
+27 −1
Original line number Original line Diff line number Diff line
@@ -78,6 +78,13 @@ public abstract class Animator implements Cloneable {
     */
     */
    private Object[] mCachedList;
    private Object[] mCachedList;


    /**
     * Tracks whether we've notified listeners of the onAnimationStart() event. This can be
     * complex to keep track of since we notify listeners at different times depending on
     * startDelay and whether start() was called before end().
     */
    boolean mStartListenersCalled = false;

    /**
    /**
     * Sets the duration for delaying pausing animators when apps go into the background.
     * Sets the duration for delaying pausing animators when apps go into the background.
     * Used by AnimationHandler when requested to pause animators.
     * Used by AnimationHandler when requested to pause animators.
@@ -165,7 +172,9 @@ public abstract class Animator implements Cloneable {
     * @see AnimatorPauseListener
     * @see AnimatorPauseListener
     */
     */
    public void pause() {
    public void pause() {
        if (isStarted() && !mPaused) {
        // We only want to pause started Animators or animators that setCurrentPlayTime()
        // have been called on. mStartListenerCalled will be true if seek has happened.
        if ((isStarted() || mStartListenersCalled) && !mPaused) {
            mPaused = true;
            mPaused = true;
            notifyPauseListeners(AnimatorCaller.ON_PAUSE);
            notifyPauseListeners(AnimatorCaller.ON_PAUSE);
        }
        }
@@ -444,6 +453,7 @@ public abstract class Animator implements Cloneable {
                anim.mPauseListeners = new ArrayList<AnimatorPauseListener>(mPauseListeners);
                anim.mPauseListeners = new ArrayList<AnimatorPauseListener>(mPauseListeners);
            }
            }
            anim.mCachedList = null;
            anim.mCachedList = null;
            anim.mStartListenersCalled = false;
            return anim;
            return anim;
        } catch (CloneNotSupportedException e) {
        } catch (CloneNotSupportedException e) {
           throw new AssertionError();
           throw new AssertionError();
@@ -608,6 +618,22 @@ public abstract class Animator implements Cloneable {
        callOnList(mPauseListeners, notification, this, false);
        callOnList(mPauseListeners, notification, this, false);
    }
    }


    void notifyStartListeners(boolean isReversing) {
        boolean startListenersCalled = mStartListenersCalled;
        mStartListenersCalled = true;
        if (mListeners != null && !startListenersCalled) {
            notifyListeners(AnimatorCaller.ON_START, isReversing);
        }
    }

    void notifyEndListeners(boolean isReversing) {
        boolean startListenersCalled = mStartListenersCalled;
        mStartListenersCalled = false;
        if (mListeners != null && startListenersCalled) {
            notifyListeners(AnimatorCaller.ON_END, isReversing);
        }
    }

    /**
    /**
     * Calls <code>call</code> for every item in <code>list</code> with <code>animator</code> and
     * Calls <code>call</code> for every item in <code>list</code> with <code>animator</code> and
     * <code>isReverse</code> as parameters.
     * <code>isReverse</code> as parameters.
+23 −29
Original line number Original line Diff line number Diff line
@@ -189,11 +189,6 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
     */
     */
    private long[] mChildStartAndStopTimes;
    private long[] mChildStartAndStopTimes;


    /**
     * Tracks whether we've notified listeners of the onAnimationStart() event.
     */
    private boolean mStartListenersCalled;

    // This is to work around a bug in b/34736819. This needs to be removed once app team
    // This is to work around a bug in b/34736819. This needs to be removed once app team
    // fixes their side.
    // fixes their side.
    private AnimatorListenerAdapter mAnimationEndListener = new AnimatorListenerAdapter() {
    private AnimatorListenerAdapter mAnimationEndListener = new AnimatorListenerAdapter() {
@@ -424,7 +419,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
        if (Looper.myLooper() == null) {
        if (Looper.myLooper() == null) {
            throw new AndroidRuntimeException("Animators may only be run on Looper threads");
            throw new AndroidRuntimeException("Animators may only be run on Looper threads");
        }
        }
        if (isStarted()) {
        if (isStarted() || mStartListenersCalled) {
            notifyListeners(AnimatorCaller.ON_CANCEL, false);
            notifyListeners(AnimatorCaller.ON_CANCEL, false);
            callOnPlayingSet(Animator::cancel);
            callOnPlayingSet(Animator::cancel);
            mPlayingSet.clear();
            mPlayingSet.clear();
@@ -486,13 +481,13 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
            return;
            return;
        }
        }
        if (isStarted()) {
        if (isStarted()) {
            mStarted = false; // don't allow reentrancy
            // Iterate the animations that haven't finished or haven't started, and end them.
            // Iterate the animations that haven't finished or haven't started, and end them.
            if (mReversing) {
            if (mReversing) {
                // Between start() and first frame, mLastEventId would be unset (i.e. -1)
                // Between start() and first frame, mLastEventId would be unset (i.e. -1)
                mLastEventId = mLastEventId == -1 ? mEvents.size() : mLastEventId;
                mLastEventId = mLastEventId == -1 ? mEvents.size() : mLastEventId;
                while (mLastEventId > 0) {
                for (int eventId = mLastEventId - 1; eventId >= 0; eventId--) {
                    mLastEventId = mLastEventId - 1;
                    AnimationEvent event = mEvents.get(eventId);
                    AnimationEvent event = mEvents.get(mLastEventId);
                    Animator anim = event.mNode.mAnimation;
                    Animator anim = event.mNode.mAnimation;
                    if (mNodeMap.get(anim).mEnded) {
                    if (mNodeMap.get(anim).mEnded) {
                        continue;
                        continue;
@@ -508,11 +503,10 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
                    }
                    }
                }
                }
            } else {
            } else {
                while (mLastEventId < mEvents.size() - 1) {
                for (int eventId = mLastEventId + 1; eventId < mEvents.size(); eventId++) {
                    // Avoid potential reentrant loop caused by child animators manipulating
                    // Avoid potential reentrant loop caused by child animators manipulating
                    // AnimatorSet's lifecycle (i.e. not a recommended approach).
                    // AnimatorSet's lifecycle (i.e. not a recommended approach).
                    mLastEventId = mLastEventId + 1;
                    AnimationEvent event = mEvents.get(eventId);
                    AnimationEvent event = mEvents.get(mLastEventId);
                    Animator anim = event.mNode.mAnimation;
                    Animator anim = event.mNode.mAnimation;
                    if (mNodeMap.get(anim).mEnded) {
                    if (mNodeMap.get(anim).mEnded) {
                        continue;
                        continue;
@@ -527,7 +521,6 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
                    }
                    }
                }
                }
            }
            }
            mPlayingSet.clear();
        }
        }
        endAnimation();
        endAnimation();
    }
    }
@@ -723,6 +716,10 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
        if (Looper.myLooper() == null) {
        if (Looper.myLooper() == null) {
            throw new AndroidRuntimeException("Animators may only be run on Looper threads");
            throw new AndroidRuntimeException("Animators may only be run on Looper threads");
        }
        }
        if (inReverse == mReversing && selfPulse == mSelfPulse && mStarted) {
            // It is already started
            return;
        }
        mStarted = true;
        mStarted = true;
        mSelfPulse = selfPulse;
        mSelfPulse = selfPulse;
        mPaused = false;
        mPaused = false;
@@ -756,20 +753,6 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
        }
        }
    }
    }


    private void notifyStartListeners(boolean inReverse) {
        if (mListeners != null && !mStartListenersCalled) {
            notifyListeners(AnimatorCaller.ON_START, inReverse);
        }
        mStartListenersCalled = true;
    }

    private void notifyEndListeners(boolean inReverse) {
        if (mListeners != null && mStartListenersCalled) {
            notifyListeners(AnimatorCaller.ON_END, inReverse);
        }
        mStartListenersCalled = false;
    }

    // Returns true if set is empty or contains nothing but animator sets with no start delay.
    // Returns true if set is empty or contains nothing but animator sets with no start delay.
    private static boolean isEmptySet(AnimatorSet set) {
    private static boolean isEmptySet(AnimatorSet set) {
        if (set.getStartDelay() > 0) {
        if (set.getStartDelay() > 0) {
@@ -936,12 +919,18 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
                                lastPlayTime - node.mStartTime,
                                lastPlayTime - node.mStartTime,
                                notify
                                notify
                        );
                        );
                        if (notify) {
                            mPlayingSet.remove(node);
                        }
                    } else if (start <= currentPlayTime && currentPlayTime <= end) {
                    } else if (start <= currentPlayTime && currentPlayTime <= end) {
                        animator.animateSkipToEnds(
                        animator.animateSkipToEnds(
                                currentPlayTime - node.mStartTime,
                                currentPlayTime - node.mStartTime,
                                lastPlayTime - node.mStartTime,
                                lastPlayTime - node.mStartTime,
                                notify
                                notify
                        );
                        );
                        if (notify && !mPlayingSet.contains(node)) {
                            mPlayingSet.add(node);
                        }
                    }
                    }
                }
                }
            }
            }
@@ -969,12 +958,18 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
                                lastPlayTime - node.mStartTime,
                                lastPlayTime - node.mStartTime,
                                notify
                                notify
                        );
                        );
                        if (notify) {
                            mPlayingSet.remove(node);
                        }
                    } else if (start <= currentPlayTime && currentPlayTime <= end) {
                    } else if (start <= currentPlayTime && currentPlayTime <= end) {
                        animator.animateSkipToEnds(
                        animator.animateSkipToEnds(
                                currentPlayTime - node.mStartTime,
                                currentPlayTime - node.mStartTime,
                                lastPlayTime - node.mStartTime,
                                lastPlayTime - node.mStartTime,
                                notify
                                notify
                        );
                        );
                        if (notify && !mPlayingSet.contains(node)) {
                            mPlayingSet.add(node);
                        }
                    }
                    }
                }
                }
            }
            }
@@ -1115,8 +1110,8 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
                mSeekState.setPlayTime(0, mReversing);
                mSeekState.setPlayTime(0, mReversing);
            }
            }
        }
        }
        animateBasedOnPlayTime(playTime, lastPlayTime, mReversing, true);
        mSeekState.setPlayTime(playTime, mReversing);
        mSeekState.setPlayTime(playTime, mReversing);
        animateBasedOnPlayTime(playTime, lastPlayTime, mReversing, true);
    }
    }


    /**
    /**
@@ -1498,7 +1493,6 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
        anim.mNodeMap = new ArrayMap<Animator, Node>();
        anim.mNodeMap = new ArrayMap<Animator, Node>();
        anim.mNodes = new ArrayList<Node>(nodeCount);
        anim.mNodes = new ArrayList<Node>(nodeCount);
        anim.mEvents = new ArrayList<AnimationEvent>();
        anim.mEvents = new ArrayList<AnimationEvent>();
        anim.mStartListenersCalled = false;
        anim.mAnimationEndListener = new AnimatorListenerAdapter() {
        anim.mAnimationEndListener = new AnimatorListenerAdapter() {
            @Override
            @Override
            public void onAnimationEnd(Animator animation) {
            public void onAnimationEnd(Animator animation) {
+7 −26
Original line number Original line Diff line number Diff line
@@ -198,13 +198,6 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
     */
     */
    private boolean mStarted = false;
    private boolean mStarted = false;


    /**
     * Tracks whether we've notified listeners of the onAnimationStart() event. This can be
     * complex to keep track of since we notify listeners at different times depending on
     * startDelay and whether start() was called before end().
     */
    private boolean mStartListenersCalled = false;

    /**
    /**
     * Flag that denotes whether the animation is set up and ready to go. Used to
     * Flag that denotes whether the animation is set up and ready to go. Used to
     * set up animation that has not yet been started.
     * set up animation that has not yet been started.
@@ -1108,20 +1101,6 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
        }
        }
    }
    }


    private void notifyStartListeners(boolean isReversing) {
        if (mListeners != null && !mStartListenersCalled) {
            notifyListeners(AnimatorCaller.ON_START, isReversing);
        }
        mStartListenersCalled = true;
    }

    private void notifyEndListeners(boolean isReversing) {
        if (mListeners != null && mStartListenersCalled) {
            notifyListeners(AnimatorCaller.ON_END, isReversing);
        }
        mStartListenersCalled = false;
    }

    /**
    /**
     * Start the animation playing. This version of start() takes a boolean flag that indicates
     * Start the animation playing. This version of start() takes a boolean flag that indicates
     * whether the animation should play in reverse. The flag is usually false, but may be set
     * whether the animation should play in reverse. The flag is usually false, but may be set
@@ -1139,6 +1118,10 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
        if (Looper.myLooper() == null) {
        if (Looper.myLooper() == null) {
            throw new AndroidRuntimeException("Animators may only be run on Looper threads");
            throw new AndroidRuntimeException("Animators may only be run on Looper threads");
        }
        }
        if (playBackwards == mResumed && mSelfPulse == !mSuppressSelfPulseRequested && mStarted) {
            // already started
            return;
        }
        mReversing = playBackwards;
        mReversing = playBackwards;
        mSelfPulse = !mSuppressSelfPulseRequested;
        mSelfPulse = !mSuppressSelfPulseRequested;
        // Special case: reversing from seek-to-0 should act as if not seeked at all.
        // Special case: reversing from seek-to-0 should act as if not seeked at all.
@@ -1209,7 +1192,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
        // Only cancel if the animation is actually running or has been started and is about
        // Only cancel if the animation is actually running or has been started and is about
        // to run
        // to run
        // Only notify listeners if the animator has actually started
        // Only notify listeners if the animator has actually started
        if ((mStarted || mRunning) && mListeners != null) {
        if ((mStarted || mRunning || mStartListenersCalled) && mListeners != null) {
            if (!mRunning) {
            if (!mRunning) {
                // If it's not yet running, then start listeners weren't called. Call them now.
                // If it's not yet running, then start listeners weren't called. Call them now.
                notifyStartListeners(mReversing);
                notifyStartListeners(mReversing);
@@ -1217,7 +1200,6 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
            notifyListeners(AnimatorCaller.ON_CANCEL, false);
            notifyListeners(AnimatorCaller.ON_CANCEL, false);
        }
        }
        endAnimation();
        endAnimation();

    }
    }


    @Override
    @Override
@@ -1320,11 +1302,11 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
            // If it's not yet running, then start listeners weren't called. Call them now.
            // If it's not yet running, then start listeners weren't called. Call them now.
            notifyStartListeners(mReversing);
            notifyStartListeners(mReversing);
        }
        }
        mRunning = false;
        mStarted = false;
        mLastFrameTime = -1;
        mLastFrameTime = -1;
        mFirstFrameTime = -1;
        mFirstFrameTime = -1;
        mStartTime = -1;
        mStartTime = -1;
        mRunning = false;
        mStarted = false;
        notifyEndListeners(mReversing);
        notifyEndListeners(mReversing);
        // mReversing needs to be reset *after* notifying the listeners for the end callbacks.
        // mReversing needs to be reset *after* notifying the listeners for the end callbacks.
        mReversing = false;
        mReversing = false;
@@ -1687,7 +1669,6 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
        anim.mRunning = false;
        anim.mRunning = false;
        anim.mPaused = false;
        anim.mPaused = false;
        anim.mResumed = false;
        anim.mResumed = false;
        anim.mStartListenersCalled = false;
        anim.mStartTime = -1;
        anim.mStartTime = -1;
        anim.mStartTimeCommitted = false;
        anim.mStartTimeCommitted = false;
        anim.mAnimationEndRequested = false;
        anim.mAnimationEndRequested = false;
+5 −3
Original line number Original line Diff line number Diff line
@@ -435,9 +435,11 @@ public class AnimatorSetActivityTest {
        mActivityRule.runOnUiThread(s::start);
        mActivityRule.runOnUiThread(s::start);


        while (!listener.endIsCalled) {
        while (!listener.endIsCalled) {
            boolean passedStartDelay = a1.isStarted() || a2.isStarted() || a3.isStarted() ||
            mActivityRule.runOnUiThread(() -> {
                    a4.isStarted() || a5.isStarted();
                boolean passedStartDelay = a1.isStarted() || a2.isStarted() || a3.isStarted()
                        || a4.isStarted() || a5.isStarted();
                assertEquals(passedStartDelay, s.isRunning());
                assertEquals(passedStartDelay, s.isRunning());
            });
            Thread.sleep(50);
            Thread.sleep(50);
        }
        }
        assertFalse(s.isRunning());
        assertFalse(s.isRunning());
+240 −15
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@
package android.animation;
package android.animation;


import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;


import android.util.PollingCheck;
import android.util.PollingCheck;
import android.view.View;
import android.view.View;
@@ -31,6 +32,8 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.Test;


import java.util.ArrayList;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;


@MediumTest
@MediumTest
public class AnimatorSetCallsTest {
public class AnimatorSetCallsTest {
@@ -40,6 +43,7 @@ public class AnimatorSetCallsTest {


    private AnimatorSetActivity mActivity;
    private AnimatorSetActivity mActivity;
    private AnimatorSet mSet1;
    private AnimatorSet mSet1;
    private AnimatorSet mSet2;
    private ObjectAnimator mAnimator;
    private ObjectAnimator mAnimator;
    private CountListener mListener1;
    private CountListener mListener1;
    private CountListener mListener2;
    private CountListener mListener2;
@@ -56,10 +60,10 @@ public class AnimatorSetCallsTest {
            mSet1.addListener(mListener1);
            mSet1.addListener(mListener1);
            mSet1.addPauseListener(mListener1);
            mSet1.addPauseListener(mListener1);


            AnimatorSet set2 = new AnimatorSet();
            mSet2 = new AnimatorSet();
            mListener2 = new CountListener();
            mListener2 = new CountListener();
            set2.addListener(mListener2);
            mSet2.addListener(mListener2);
            set2.addPauseListener(mListener2);
            mSet2.addPauseListener(mListener2);


            mAnimator = ObjectAnimator.ofFloat(square, "translationX", 0f, 100f);
            mAnimator = ObjectAnimator.ofFloat(square, "translationX", 0f, 100f);
            mListener3 = new CountListener();
            mListener3 = new CountListener();
@@ -67,8 +71,8 @@ public class AnimatorSetCallsTest {
            mAnimator.addPauseListener(mListener3);
            mAnimator.addPauseListener(mListener3);
            mAnimator.setDuration(1);
            mAnimator.setDuration(1);


            set2.play(mAnimator);
            mSet2.play(mAnimator);
            mSet1.play(set2);
            mSet1.play(mSet2);
        });
        });
    }
    }


@@ -175,6 +179,7 @@ public class AnimatorSetCallsTest {
        assertEquals(1, updateValues.size());
        assertEquals(1, updateValues.size());
        assertEquals(0f, updateValues.get(0), 0f);
        assertEquals(0f, updateValues.get(0), 0f);
    }
    }

    @Test
    @Test
    public void updateOnlyWhileRunning() {
    public void updateOnlyWhileRunning() {
        ArrayList<Float> updateValues = new ArrayList<>();
        ArrayList<Float> updateValues = new ArrayList<>();
@@ -207,6 +212,226 @@ public class AnimatorSetCallsTest {
        }
        }
    }
    }


    @Test
    public void pauseResumeSeekingAnimators() {
        ValueAnimator animator2 = ValueAnimator.ofFloat(0f, 1f);
        mSet2.play(animator2).after(mAnimator);
        mSet2.setStartDelay(100);
        mSet1.setStartDelay(100);
        mAnimator.setDuration(100);

        mActivity.runOnUiThread(() -> {
            mSet1.setCurrentPlayTime(0);
            mSet1.pause();

            // only startForward and pause should have been called once
            mListener1.assertValues(
                    1, 0, 0, 0, 0, 0, 1, 0
            );
            mListener2.assertValues(
                    0, 0, 0, 0, 0, 0, 0, 0
            );
            mListener3.assertValues(
                    0, 0, 0, 0, 0, 0, 0, 0
            );

            mSet1.resume();
            mListener1.assertValues(
                    1, 0, 0, 0, 0, 0, 1, 1
            );
            mListener2.assertValues(
                    0, 0, 0, 0, 0, 0, 0, 0
            );
            mListener3.assertValues(
                    0, 0, 0, 0, 0, 0, 0, 0
            );

            mSet1.setCurrentPlayTime(200);

            // resume and endForward should have been called once
            mListener1.assertValues(
                    1, 0, 0, 0, 0, 0, 1, 1
            );
            mListener2.assertValues(
                    1, 0, 0, 0, 0, 0, 0, 0
            );
            mListener3.assertValues(
                    1, 0, 0, 0, 0, 0, 0, 0
            );

            mSet1.pause();
            mListener1.assertValues(
                    1, 0, 0, 0, 0, 0, 2, 1
            );
            mListener2.assertValues(
                    1, 0, 0, 0, 0, 0, 1, 0
            );
            mListener3.assertValues(
                    1, 0, 0, 0, 0, 0, 1, 0
            );
            mSet1.resume();
            mListener1.assertValues(
                    1, 0, 0, 0, 0, 0, 2, 2
            );
            mListener2.assertValues(
                    1, 0, 0, 0, 0, 0, 1, 1
            );
            mListener3.assertValues(
                    1, 0, 0, 0, 0, 0, 1, 1
            );

            // now go to animator2
            mSet1.setCurrentPlayTime(400);
            mSet1.pause();
            mSet1.resume();
            mListener1.assertValues(
                    1, 0, 0, 0, 0, 0, 3, 3
            );
            mListener2.assertValues(
                    1, 0, 0, 0, 0, 0, 2, 2
            );
            mListener3.assertValues(
                    1, 0, 1, 0, 0, 0, 1, 1
            );

            // now go back to mAnimator
            mSet1.setCurrentPlayTime(250);
            mSet1.pause();
            mSet1.resume();
            mListener1.assertValues(
                    1, 0, 0, 0, 0, 0, 4, 4
            );
            mListener2.assertValues(
                    1, 0, 0, 0, 0, 0, 3, 3
            );
            mListener3.assertValues(
                    1, 1, 1, 0, 0, 0, 2, 2
            );

            // now go back to before mSet2 was being run
            mSet1.setCurrentPlayTime(1);
            mSet1.pause();
            mSet1.resume();
            mListener1.assertValues(
                    1, 0, 0, 0, 0, 0, 5, 5
            );
            mListener2.assertValues(
                    1, 0, 0, 1, 0, 0, 3, 3
            );
            mListener3.assertValues(
                    1, 1, 1, 1, 0, 0, 2, 2
            );
        });
    }

    @Test
    public void endInCancel() throws Throwable {
        AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
            @Override
            public void onAnimationCancel(Animator animation) {
                mSet1.end();
            }
        };
        mSet1.addListener(listener);
        mActivity.runOnUiThread(() -> {
            mSet1.start();
            mSet1.cancel();
            // Should go to the end value
            View square = mActivity.findViewById(R.id.square1);
            assertEquals(100f, square.getTranslationX(), 0.001f);
        });
    }

    @Test
    public void reentrantStart() throws Throwable {
        CountDownLatch latch = new CountDownLatch(3);
        AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation, boolean isReverse) {
                mSet1.start();
                latch.countDown();
            }
        };
        mSet1.addListener(listener);
        mSet2.addListener(listener);
        mAnimator.addListener(listener);
        mActivity.runOnUiThread(() -> mSet1.start());
        assertTrue(latch.await(1, TimeUnit.SECONDS));

        // Make sure that the UI thread hasn't been destroyed by a stack overflow...
        mActivity.runOnUiThread(() -> {});
    }

    @Test
    public void reentrantEnd() throws Throwable {
        CountDownLatch latch = new CountDownLatch(3);
        AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation, boolean isReverse) {
                mSet1.end();
                latch.countDown();
            }
        };
        mSet1.addListener(listener);
        mSet2.addListener(listener);
        mAnimator.addListener(listener);
        mActivity.runOnUiThread(() -> {
            mSet1.start();
            mSet1.end();
        });
        assertTrue(latch.await(1, TimeUnit.SECONDS));

        // Make sure that the UI thread hasn't been destroyed by a stack overflow...
        mActivity.runOnUiThread(() -> {});
    }

    @Test
    public void reentrantPause() throws Throwable {
        CountDownLatch latch = new CountDownLatch(3);
        AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
            @Override
            public void onAnimationPause(Animator animation) {
                mSet1.pause();
                latch.countDown();
            }
        };
        mSet1.addPauseListener(listener);
        mSet2.addPauseListener(listener);
        mAnimator.addPauseListener(listener);
        mActivity.runOnUiThread(() -> {
            mSet1.start();
            mSet1.pause();
        });
        assertTrue(latch.await(1, TimeUnit.SECONDS));

        // Make sure that the UI thread hasn't been destroyed by a stack overflow...
        mActivity.runOnUiThread(() -> {});
    }

    @Test
    public void reentrantResume() throws Throwable {
        CountDownLatch latch = new CountDownLatch(3);
        AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
            @Override
            public void onAnimationResume(Animator animation) {
                mSet1.resume();
                latch.countDown();
            }
        };
        mSet1.addPauseListener(listener);
        mSet2.addPauseListener(listener);
        mAnimator.addPauseListener(listener);
        mActivity.runOnUiThread(() -> {
            mSet1.start();
            mSet1.pause();
            mSet1.resume();
        });
        assertTrue(latch.await(1, TimeUnit.SECONDS));

        // Make sure that the UI thread hasn't been destroyed by a stack overflow...
        mActivity.runOnUiThread(() -> {});
    }

    private void waitForOnUiThread(PollingCheck.PollingCheckCondition condition) {
    private void waitForOnUiThread(PollingCheck.PollingCheckCondition condition) {
        final boolean[] value = new boolean[1];
        final boolean[] value = new boolean[1];
        PollingCheck.waitFor(() -> {
        PollingCheck.waitFor(() -> {
@@ -238,16 +463,16 @@ public class AnimatorSetCallsTest {
                int pause,
                int pause,
                int resume
                int resume
        ) {
        ) {
            assertEquals(0, startNoParam);
            assertEquals("onAnimationStart() without direction", 0, startNoParam);
            assertEquals(0, endNoParam);
            assertEquals("onAnimationEnd() without direction", 0, endNoParam);
            assertEquals(startForward, this.startForward);
            assertEquals("onAnimationStart(forward)", startForward, this.startForward);
            assertEquals(startReverse, this.startReverse);
            assertEquals("onAnimationStart(reverse)", startReverse, this.startReverse);
            assertEquals(endForward, this.endForward);
            assertEquals("onAnimationEnd(forward)", endForward, this.endForward);
            assertEquals(endReverse, this.endReverse);
            assertEquals("onAnimationEnd(reverse)", endReverse, this.endReverse);
            assertEquals(cancel, this.cancel);
            assertEquals("onAnimationCancel()", cancel, this.cancel);
            assertEquals(repeat, this.repeat);
            assertEquals("onAnimationRepeat()", repeat, this.repeat);
            assertEquals(pause, this.pause);
            assertEquals("onAnimationPause()", pause, this.pause);
            assertEquals(resume, this.resume);
            assertEquals("onAnimationResume()", resume, this.resume);
        }
        }


        @Override
        @Override
Loading