• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package android.animation.cts;
17 
18 import static com.android.compatibility.common.util.CtsMockitoUtils.within;
19 
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertFalse;
22 import static org.junit.Assert.assertSame;
23 import static org.junit.Assert.assertTrue;
24 import static org.mockito.Mockito.any;
25 import static org.mockito.Mockito.mock;
26 import static org.mockito.Mockito.never;
27 import static org.mockito.Mockito.timeout;
28 import static org.mockito.Mockito.times;
29 import static org.mockito.Mockito.verify;
30 
31 import android.animation.Animator;
32 import android.animation.AnimatorListenerAdapter;
33 import android.animation.AnimatorSet;
34 import android.animation.ObjectAnimator;
35 import android.animation.TimeInterpolator;
36 import android.animation.ValueAnimator;
37 import android.os.SystemClock;
38 import android.view.View;
39 import android.view.animation.AccelerateDecelerateInterpolator;
40 import android.view.animation.AccelerateInterpolator;
41 import android.view.animation.LinearInterpolator;
42 
43 import androidx.annotation.NonNull;
44 import androidx.test.InstrumentationRegistry;
45 import androidx.test.filters.MediumTest;
46 import androidx.test.rule.ActivityTestRule;
47 import androidx.test.runner.AndroidJUnit4;
48 
49 import org.junit.After;
50 import org.junit.Before;
51 import org.junit.Rule;
52 import org.junit.Test;
53 import org.junit.runner.RunWith;
54 
55 import java.util.ArrayList;
56 import java.util.HashSet;
57 import java.util.List;
58 import java.util.Set;
59 import java.util.concurrent.CountDownLatch;
60 import java.util.concurrent.TimeUnit;
61 
62 @MediumTest
63 @RunWith(AndroidJUnit4.class)
64 public class AnimatorSetTest {
65     private AnimationActivity mActivity;
66     private AnimatorSet mAnimatorSet;
67     private float mPreviousDurationScale = 1.0f;
68     private long mDuration = 1000;
69     private Object object;
70     private ObjectAnimator yAnimator;
71     private ObjectAnimator xAnimator;
72     Set<Integer> identityHashes = new HashSet<>();
73     private static final float EPSILON = 0.001f;
74 
75     @Rule
76     public ActivityTestRule<AnimationActivity> mActivityRule =
77             new ActivityTestRule<>(AnimationActivity.class);
78 
79     @Before
setup()80     public void setup() {
81         InstrumentationRegistry.getInstrumentation().setInTouchMode(false);
82         mActivity = mActivityRule.getActivity();
83         mPreviousDurationScale = ValueAnimator.getDurationScale();
84         ValueAnimator.setDurationScale(1.0f);
85         object = mActivity.view.newBall;
86         yAnimator = getYAnimator(object);
87         xAnimator = getXAnimator(object);
88     }
89 
90     @After
tearDown()91     public void tearDown() {
92         ValueAnimator.setDurationScale(mPreviousDurationScale);
93     }
94 
95     @Test
testPlaySequentially()96     public void testPlaySequentially() throws Throwable {
97         xAnimator.setRepeatCount(0);
98         yAnimator.setRepeatCount(0);
99         xAnimator.setDuration(50);
100         yAnimator.setDuration(50);
101         List<Animator> animators = new ArrayList<Animator>();
102         animators.add(xAnimator);
103         animators.add(yAnimator);
104         mAnimatorSet = new AnimatorSet();
105         mAnimatorSet.playSequentially(animators);
106         verifySequentialPlayOrder(mAnimatorSet, new Animator[] {xAnimator, yAnimator});
107 
108         ValueAnimator anim1 = ValueAnimator.ofFloat(0f, 1f);
109         ValueAnimator anim2 = ValueAnimator.ofInt(0, 100);
110         anim1.setDuration(50);
111         anim2.setDuration(50);
112         AnimatorSet set = new AnimatorSet();
113         set.playSequentially(anim1, anim2);
114         verifySequentialPlayOrder(set, new Animator[] {anim1, anim2});
115     }
116 
117     /**
118      * Start the animator, and verify the animators are played sequentially in the order that is
119      * defined in the array.
120      *
121      * @param set AnimatorSet to be started and verified
122      * @param animators animators that we put in the AnimatorSet, in the order that they'll play
123      */
verifySequentialPlayOrder(final AnimatorSet set, Animator[] animators)124     private void verifySequentialPlayOrder(final AnimatorSet set, Animator[] animators)
125             throws Throwable {
126 
127         final MyListener[] listeners = new MyListener[animators.length];
128         for (int i = 0; i < animators.length; i++) {
129             if (i == 0) {
130                 listeners[i] = new MyListener();
131             } else {
132                 final int current = i;
133                 listeners[i] = new MyListener() {
134                     @Override
135                     public void onAnimationStart(Animator anim) {
136                         super.onAnimationStart(anim);
137                         // Check that the previous animator has finished.
138                         assertTrue(listeners[current - 1].mEndIsCalled);
139                     }
140                 };
141             }
142             animators[i].addListener(listeners[i]);
143         }
144 
145         final CountDownLatch startLatch = new CountDownLatch(1);
146         final CountDownLatch endLatch = new CountDownLatch(1);
147 
148         set.addListener(new MyListener() {
149             @Override
150             public void onAnimationEnd(Animator anim) {
151                 endLatch.countDown();
152             }
153         });
154 
155         long totalDuration = set.getTotalDuration();
156         assertFalse(set.isRunning());
157         mActivityRule.runOnUiThread(() -> {
158             set.start();
159             startLatch.countDown();
160         });
161 
162         // Set timeout to 100ms, if current count reaches 0 before the timeout, startLatch.await(...)
163         // will return immediately.
164         assertTrue(startLatch.await(100, TimeUnit.MILLISECONDS));
165         assertTrue(set.isRunning());
166         assertTrue(endLatch.await(totalDuration * 2, TimeUnit.MILLISECONDS));
167         // Check that all the animators have finished.
168         for (int i = 0; i < listeners.length; i++) {
169             assertTrue(listeners[i].mEndIsCalled);
170         }
171 
172         // Now reverse the animations and verify whether the play order is reversed.
173         for (int i = 0; i < animators.length; i++) {
174             if (i == animators.length - 1) {
175                 listeners[i] = new MyListener();
176             } else {
177                 final int current = i;
178                 listeners[i] = new MyListener() {
179                     @Override
180                     public void onAnimationStart(Animator anim) {
181                         super.onAnimationStart(anim);
182                         // Check that the previous animator has finished.
183                         assertTrue(listeners[current + 1].mEndIsCalled);
184                     }
185                 };
186             }
187             animators[i].removeAllListeners();
188             animators[i].addListener(listeners[i]);
189         }
190 
191         mActivityRule.runOnUiThread(() -> {
192             set.reverse();
193             startLatch.countDown();
194         });
195 
196         // Set timeout to 100ms, if current count reaches 0 before the timeout, startLatch.await(..)
197         // will return immediately.
198         assertTrue(startLatch.await(100, TimeUnit.MILLISECONDS));
199         assertTrue(set.isRunning());
200         assertTrue(endLatch.await(totalDuration * 2, TimeUnit.MILLISECONDS));
201 
202     }
203 
204     @Test
testPlayTogether()205     public void testPlayTogether() throws Throwable {
206         xAnimator.setRepeatCount(ValueAnimator.INFINITE);
207         Animator[] animatorArray = {xAnimator, yAnimator};
208 
209         mAnimatorSet = new AnimatorSet();
210         mAnimatorSet.playTogether(animatorArray);
211 
212         assertFalse(mAnimatorSet.isRunning());
213         assertFalse(xAnimator.isRunning());
214         assertFalse(yAnimator.isRunning());
215         startAnimation(mAnimatorSet);
216         SystemClock.sleep(100);
217         assertTrue(mAnimatorSet.isRunning());
218         assertTrue(xAnimator.isRunning());
219         assertTrue(yAnimator.isRunning());
220 
221         // Now assemble another animator set
222         ValueAnimator anim1 = ValueAnimator.ofFloat(0f, 100f);
223         ValueAnimator anim2 = ValueAnimator.ofFloat(10f, 100f);
224         AnimatorSet set = new AnimatorSet();
225         set.playTogether(anim1, anim2);
226 
227         assertFalse(set.isRunning());
228         assertFalse(anim1.isRunning());
229         assertFalse(anim2.isRunning());
230         startAnimation(set);
231         SystemClock.sleep(100);
232         assertTrue(set.isRunning());
233         assertTrue(anim1.isRunning());
234         assertTrue(anim2.isRunning());
235     }
236 
237     @Test
testPlayBeforeAfter()238     public void testPlayBeforeAfter() throws Throwable {
239         xAnimator.setRepeatCount(0);
240         yAnimator.setRepeatCount(0);
241         final ValueAnimator zAnimator = ValueAnimator.ofFloat(0f, 100f);
242 
243         xAnimator.setDuration(50);
244         yAnimator.setDuration(50);
245         zAnimator.setDuration(50);
246 
247         AnimatorSet set = new AnimatorSet();
248         set.play(yAnimator).before(zAnimator).after(xAnimator);
249 
250         verifySequentialPlayOrder(set, new Animator[] {xAnimator, yAnimator, zAnimator});
251     }
252 
253     @Test
testListenerCallbackOnEmptySet()254     public void testListenerCallbackOnEmptySet() throws Throwable {
255         // Create an AnimatorSet that only contains one empty AnimatorSet, and checks the callback
256         // sequence by checking the time stamps of the callbacks.
257         final AnimatorSet emptySet = new AnimatorSet();
258         final AnimatorSet set = new AnimatorSet();
259         set.play(emptySet);
260         MyListener listener = new MyListener() {
261             long startTime = 0;
262             long endTime = 0;
263             @Override
264             public void onAnimationStart(Animator animation) {
265                 super.onAnimationStart(animation);
266                 startTime = SystemClock.currentThreadTimeMillis();
267             }
268 
269             @Override
270             public void onAnimationEnd(Animator animation) {
271                 super.onAnimationEnd(animation);
272                 endTime = SystemClock.currentThreadTimeMillis();
273                 assertTrue(endTime >= startTime);
274                 assertTrue(startTime != 0);
275             }
276         };
277         set.addListener(listener);
278         mActivityRule.runOnUiThread(() -> {
279             set.start();
280         });
281         assertTrue(listener.mStartIsCalled);
282         assertTrue(listener.mEndIsCalled);
283     }
284 
285     @Test
testPauseAndResume()286     public void testPauseAndResume() throws Throwable {
287         final AnimatorSet set = new AnimatorSet();
288         ValueAnimator a1 = ValueAnimator.ofFloat(0f, 100f);
289         a1.setDuration(50);
290         ValueAnimator a2 = ValueAnimator.ofFloat(0f, 100f);
291         a2.setDuration(50);
292         a1.addListener(new AnimatorListenerAdapter() {
293             @Override
294             public void onAnimationStart(Animator animation) {
295                 // Pause non-delayed set once the child animator starts
296                 set.pause();
297             }
298         });
299         set.playTogether(a1, a2);
300 
301         final AnimatorSet delayedSet = new AnimatorSet();
302         ValueAnimator a3 = ValueAnimator.ofFloat(0f, 100f);
303         a3.setDuration(50);
304         ValueAnimator a4 = ValueAnimator.ofFloat(0f, 100f);
305         a4.setDuration(50);
306         delayedSet.playSequentially(a3, a4);
307         delayedSet.setStartDelay(50);
308 
309         MyListener l1 = new MyListener();
310         MyListener l2 = new MyListener();
311         set.addListener(l1);
312         delayedSet.addListener(l2);
313 
314         mActivityRule.runOnUiThread(() -> {
315             set.start();
316             delayedSet.start();
317 
318             // Pause the delayed set during start delay
319             delayedSet.pause();
320         });
321 
322         // Sleep long enough so that if the sets are not properly paused, they would have
323         // finished.
324         SystemClock.sleep(300);
325         // Verify that both sets have been paused and *not* finished.
326         assertTrue(set.isPaused());
327         assertTrue(delayedSet.isPaused());
328         assertTrue(l1.mStartIsCalled);
329         assertTrue(l2.mStartIsCalled);
330         assertFalse(l1.mEndIsCalled);
331         assertFalse(l2.mEndIsCalled);
332 
333         mActivityRule.runOnUiThread(() -> {
334             set.resume();
335             delayedSet.resume();
336         });
337         SystemClock.sleep(300);
338 
339         assertFalse(set.isPaused());
340         assertFalse(delayedSet.isPaused());
341         assertTrue(l1.mEndIsCalled);
342         assertTrue(l2.mEndIsCalled);
343     }
344 
345     @Test
testPauseBeforeStart()346     public void testPauseBeforeStart() throws Throwable {
347         final AnimatorSet set = new AnimatorSet();
348         ValueAnimator a1 = ValueAnimator.ofFloat(0f, 100f);
349         a1.setDuration(50);
350         ValueAnimator a2 = ValueAnimator.ofFloat(0f, 100f);
351         a2.setDuration(50);
352         set.setStartDelay(50);
353         set.playSequentially(a1, a2);
354 
355         final MyListener listener = new MyListener();
356         set.addListener(listener);
357 
358         mActivityRule.runOnUiThread(() -> {
359             // Pause animator set before calling start()
360             set.pause();
361             // Verify that pause should have no effect on a not-yet-started animator.
362             assertFalse(set.isPaused());
363             set.start();
364         });
365         SystemClock.sleep(300);
366 
367         // Animator set should finish running by now since it's not paused.
368         assertTrue(listener.mStartIsCalled);
369         assertTrue(listener.mEndIsCalled);
370     }
371 
372     @Test
testSeekAfterPause()373     public void testSeekAfterPause() throws Throwable {
374         final AnimatorSet set = new AnimatorSet();
375         ValueAnimator a1 = ValueAnimator.ofFloat(0f, 50f);
376         a1.setDuration(50);
377         ValueAnimator a2 = ValueAnimator.ofFloat(50, 100f);
378         a2.setDuration(50);
379         set.playSequentially(a1, a2);
380         set.setInterpolator(new LinearInterpolator());
381 
382         mActivityRule.runOnUiThread(() -> {
383             set.start();
384             set.pause();
385             set.setCurrentPlayTime(60);
386             assertEquals((long) set.getCurrentPlayTime(), 60);
387             assertEquals((float) a1.getAnimatedValue(), 50f, EPSILON);
388             assertEquals((float) a2.getAnimatedValue(), 60f, EPSILON);
389 
390             set.setCurrentPlayTime(40);
391             assertEquals((long) set.getCurrentPlayTime(), 40);
392             assertEquals((float) a1.getAnimatedValue(), 40f, EPSILON);
393             assertEquals((float) a2.getAnimatedValue(), 50f, EPSILON);
394 
395             set.cancel();
396         });
397     }
398 
399     @Test
testDuration()400     public void testDuration() throws Throwable {
401         xAnimator.setRepeatCount(ValueAnimator.INFINITE);
402         Animator[] animatorArray = { xAnimator, yAnimator };
403 
404         mAnimatorSet = new AnimatorSet();
405         mAnimatorSet.playTogether(animatorArray);
406         mAnimatorSet.setDuration(1000);
407 
408         startAnimation(mAnimatorSet);
409         SystemClock.sleep(100);
410         assertEquals(mAnimatorSet.getDuration(), 1000);
411     }
412 
413     @Test
testStartDelay()414     public void testStartDelay() throws Throwable {
415         xAnimator.setRepeatCount(ValueAnimator.INFINITE);
416         Animator[] animatorArray = { xAnimator, yAnimator };
417 
418         mAnimatorSet = new AnimatorSet();
419         mAnimatorSet.playTogether(animatorArray);
420         mAnimatorSet.setStartDelay(10);
421 
422         startAnimation(mAnimatorSet);
423         SystemClock.sleep(100);
424         assertEquals(mAnimatorSet.getStartDelay(), 10);
425     }
426 
427     /**
428      * This test sets up an AnimatorSet with start delay. One of the child animators also has
429      * start delay. We then verify that start delay was handled correctly on both AnimatorSet
430      * and individual animator level.
431      */
432     @Test
testReverseWithStartDelay()433     public void testReverseWithStartDelay() throws Throwable {
434         ValueAnimator a1 = ValueAnimator.ofFloat(0f, 1f);
435         a1.setDuration(200);
436         Animator.AnimatorListener listener1 = mock(AnimatorListenerAdapter.class);
437         a1.addListener(listener1);
438 
439         ValueAnimator a2 = ValueAnimator.ofFloat(1f, 2f);
440         a2.setDuration(200);
441         // Set start delay on a2 so that the delay is passed 100ms after a1 is finished.
442         a2.setStartDelay(300);
443         Animator.AnimatorListener listener = mock(AnimatorListenerAdapter.class);
444         a2.addListener(listener);
445 
446         a2.addListener(new AnimatorListenerAdapter() {
447             @Override
448             public void onAnimationEnd(Animator animation, boolean inReverse) {
449                 assertTrue(inReverse);
450                 // By the time a2 finishes reversing, a1 should not have started.
451                 assertFalse(a1.isStarted());
452             }
453         });
454 
455         AnimatorSet set = new AnimatorSet();
456         set.playTogether(a1, a2);
457         set.setStartDelay(1000);
458         Animator.AnimatorListener setListener = mock(AnimatorListenerAdapter.class);
459         set.addListener(setListener);
460         mActivityRule.runOnUiThread(() -> {
461             set.reverse();
462             assertTrue(a2.isStarted());
463             assertTrue(a2.isRunning());
464         });
465 
466         // a2 should finish 200ms after reverse started
467         verify(listener, within(300)).onAnimationEnd(a2, true);
468         // When a2 finishes, a1 should not have started yet
469         verify(listener1, never()).onAnimationStart(a1, true);
470 
471         // The whole set should finish within 500ms, i.e. 300ms after a2 is finished. This verifies
472         // that the AnimatorSet didn't mistakenly use its start delay in the reverse run.
473         verify(setListener, within(400)).onAnimationEnd(set, true);
474         verify(listener1, times(1)).onAnimationEnd(a1, true);
475 
476     }
477 
478     /**
479      * Test that duration scale is handled correctly in the AnimatorSet.
480      */
481     @Test
testZeroDurationScale()482     public void testZeroDurationScale() throws Throwable {
483         ValueAnimator.setDurationScale(0);
484 
485         ValueAnimator a1 = ValueAnimator.ofFloat(0f, 1f);
486         a1.setDuration(200);
487         Animator.AnimatorListener listener1 = mock(AnimatorListenerAdapter.class);
488         a1.addListener(listener1);
489 
490         ValueAnimator a2 = ValueAnimator.ofFloat(1f, 2f);
491         a2.setDuration(200);
492         // Set start delay on a2 so that the delay is passed 100ms after a1 is finished.
493         a2.setStartDelay(300);
494         Animator.AnimatorListener listener2 = mock(AnimatorListenerAdapter.class);
495         a2.addListener(listener2);
496 
497         AnimatorSet set = new AnimatorSet();
498         set.playSequentially(a1, a2);
499         set.setStartDelay(1000);
500         Animator.AnimatorListener setListener = mock(AnimatorListenerAdapter.class);
501         set.addListener(setListener);
502 
503         mActivityRule.runOnUiThread(() -> {
504             set.start();
505             verify(setListener, times(0)).onAnimationEnd(any(AnimatorSet.class),
506                     any(boolean.class));
507         });
508         verify(setListener, within(100)).onAnimationEnd(set, false);
509         verify(listener1, times(1)).onAnimationEnd(a1, false);
510         verify(listener2, times(1)).onAnimationEnd(a2, false);
511     }
512 
513     /**
514      * Test that non-zero duration scale is handled correctly in the AnimatorSet.
515      */
516     @Test
testDurationScale()517     public void testDurationScale() throws Throwable {
518         // Change the duration scale to 3
519         ValueAnimator.setDurationScale(3f);
520 
521         ValueAnimator a1 = ValueAnimator.ofFloat(0f, 1f);
522         a1.setDuration(100);
523         Animator.AnimatorListener listener1 = mock(AnimatorListenerAdapter.class);
524         a1.addListener(listener1);
525 
526         ValueAnimator a2 = ValueAnimator.ofFloat(1f, 2f);
527         a2.setDuration(100);
528         // Set start delay on a2 so that the delay is passed 100ms after a1 is finished.
529         a2.setStartDelay(200);
530         Animator.AnimatorListener listener2 = mock(AnimatorListenerAdapter.class);
531         a2.addListener(listener2);
532 
533         AnimatorSet set = new AnimatorSet();
534         set.playSequentially(a1, a2);
535         Animator.AnimatorListener setListener = mock(AnimatorListenerAdapter.class);
536         set.addListener(setListener);
537         set.setStartDelay(200);
538 
539         mActivityRule.runOnUiThread(() -> {
540             set.start();
541         });
542 
543         // Sleep for part of the start delay and check that no child animator has started, to verify
544         // that the duration scale has been properly scaled.
545         SystemClock.sleep(400);
546         // start delay of the set should be scaled to 600ms
547         verify(listener1, never()).onAnimationStart(a1, false);
548         verify(listener2, never()).onAnimationStart(a2, false);
549 
550         verify(listener1, within(400)).onAnimationStart(a1, false);
551         // Verify that a1 finish in ~300ms (3x its defined duration)
552         verify(listener1, within(500)).onAnimationEnd(a1, false);
553 
554         // a2 should be in the delayed stage after a1 is finished
555         assertTrue(a2.isStarted());
556         assertFalse(a2.isRunning());
557 
558         verify(listener2, within(800)).onAnimationStart(a2, false);
559         assertTrue(a2.isRunning());
560 
561         // Verify that the AnimatorSet has finished within 1650ms since the start of the animation.
562         // The duration of the set is 500ms, duration scale = 3.
563         verify(setListener, within(500)).onAnimationEnd(set, false);
564         verify(listener1, times(1)).onAnimationEnd(a1, false);
565         verify(listener2, times(1)).onAnimationEnd(a2, false);
566     }
567 
568     /**
569      * This test sets up 10 animators playing together. We expect the start time for all animators
570      * to be the same.
571      */
572     @Test
testMultipleAnimatorsPlayTogether()573     public void testMultipleAnimatorsPlayTogether() throws Throwable {
574         Animator[] animators = new Animator[10];
575         for (int i = 0; i < 10; i++) {
576             animators[i] = ValueAnimator.ofFloat(0f, 1f);
577         }
578         AnimatorSet set = new AnimatorSet();
579         set.playTogether(animators);
580         set.setStartDelay(80);
581 
582         Animator.AnimatorListener setListener = mock(AnimatorListenerAdapter.class);
583         set.addListener(setListener);
584         mActivityRule.runOnUiThread(() -> {
585             set.start();
586         });
587         SystemClock.sleep(150);
588         for (int i = 0; i < 10; i++) {
589             assertTrue(animators[i].isRunning());
590         }
591 
592         verify(setListener, within(400)).onAnimationEnd(set, false);
593     }
594 
595     @Test
testGetChildAnimations()596     public void testGetChildAnimations() throws Throwable {
597         Animator[] animatorArray = { xAnimator, yAnimator };
598 
599         mAnimatorSet = new AnimatorSet();
600         mAnimatorSet.getChildAnimations();
601         assertEquals(0, mAnimatorSet.getChildAnimations().size());
602         mAnimatorSet.playSequentially(animatorArray);
603         assertEquals(2, mAnimatorSet.getChildAnimations().size());
604     }
605 
606     @Test
testSetInterpolator()607     public void testSetInterpolator() throws Throwable {
608         xAnimator.setRepeatCount(ValueAnimator.INFINITE);
609         Animator[] animatorArray = {xAnimator, yAnimator};
610         TimeInterpolator interpolator = new AccelerateDecelerateInterpolator();
611         mAnimatorSet = new AnimatorSet();
612         mAnimatorSet.playTogether(animatorArray);
613         mAnimatorSet.setInterpolator(interpolator);
614 
615         assertFalse(mAnimatorSet.isRunning());
616         startAnimation(mAnimatorSet);
617         SystemClock.sleep(100);
618 
619         ArrayList<Animator> animatorList = mAnimatorSet.getChildAnimations();
620         assertEquals(interpolator, animatorList.get(0).getInterpolator());
621         assertEquals(interpolator, animatorList.get(1).getInterpolator());
622     }
623 
getXAnimator(Object object)624     private ObjectAnimator getXAnimator(Object object) {
625         String propertyX = "x";
626         float startX = mActivity.mStartX;
627         float endX = mActivity.mStartX + mActivity.mDeltaX;
628         ObjectAnimator xAnimator = ObjectAnimator.ofFloat(object, propertyX, startX, endX);
629         xAnimator.setDuration(mDuration);
630         xAnimator.setRepeatCount(ValueAnimator.INFINITE);
631         xAnimator.setInterpolator(new AccelerateInterpolator());
632         xAnimator.setRepeatMode(ValueAnimator.REVERSE);
633         return xAnimator;
634     }
635 
getYAnimator(Object object)636     private ObjectAnimator getYAnimator(Object object) {
637          String property = "y";
638          float startY = mActivity.mStartY;
639          float endY = mActivity.mStartY + mActivity.mDeltaY;
640          ObjectAnimator yAnimator = ObjectAnimator.ofFloat(object, property, startY, endY);
641          yAnimator.setDuration(mDuration);
642          yAnimator.setRepeatCount(2);
643          yAnimator.setInterpolator(new AccelerateInterpolator());
644          yAnimator.setRepeatMode(ValueAnimator.REVERSE);
645         return yAnimator;
646     }
647 
startAnimation(final AnimatorSet animatorSet)648     private void startAnimation(final AnimatorSet animatorSet) throws Throwable {
649         mActivityRule.runOnUiThread(() -> mActivity.startAnimatorSet(animatorSet));
650     }
651 
assertUnique(Object object)652     private void assertUnique(Object object) {
653         assertUnique(object, "");
654     }
655 
assertUnique(Object object, String msg)656     private void assertUnique(Object object, String msg) {
657         final int code = System.identityHashCode(object);
658         assertTrue("object should be unique " + msg + ", obj:" + object, identityHashes.add(code));
659 
660     }
661 
662     @Test
testClone()663     public void testClone() throws Throwable {
664         final AnimatorSet set1 = new AnimatorSet();
665         final AnimatorListenerAdapter setListener = new AnimatorListenerAdapter() {};
666         set1.addListener(setListener);
667         ObjectAnimator animator1 = new ObjectAnimator();
668         animator1.setDuration(100);
669         animator1.setPropertyName("x");
670         animator1.setIntValues(5);
671         animator1.setInterpolator(new LinearInterpolator());
672         AnimatorListenerAdapter listener1 = new AnimatorListenerAdapter(){};
673         AnimatorListenerAdapter listener2 = new AnimatorListenerAdapter(){};
674         animator1.addListener(listener1);
675 
676         ObjectAnimator animator2 = new ObjectAnimator();
677         animator2.setDuration(100);
678         animator2.setInterpolator(new LinearInterpolator());
679         animator2.addListener(listener2);
680         animator2.setPropertyName("y");
681         animator2.setIntValues(10);
682 
683         set1.playTogether(animator1, animator2);
684 
685         AnimateObject target = new AnimateObject();
686         set1.setTarget(target);
687         mActivityRule.runOnUiThread(set1::start);
688         assertTrue(set1.isStarted());
689 
690         animator1.getListeners();
691         AnimatorSet set2 = set1.clone();
692         assertFalse(set2.isStarted());
693 
694         assertUnique(set1);
695         assertUnique(animator1);
696         assertUnique(animator2);
697 
698         assertUnique(set2);
699         assertEquals(2, set2.getChildAnimations().size());
700 
701         Animator clone1 = set2.getChildAnimations().get(0);
702         Animator clone2 = set2.getChildAnimations().get(1);
703 
704         for (Animator animator : set2.getChildAnimations()) {
705             assertUnique(animator);
706         }
707 
708         assertTrue(clone1.getListeners().contains(listener1));
709         assertTrue(clone2.getListeners().contains(listener2));
710 
711         assertTrue(set2.getListeners().contains(setListener));
712 
713         for (Animator.AnimatorListener listener : set1.getListeners()) {
714             assertTrue(set2.getListeners().contains(listener));
715         }
716 
717         assertEquals(animator1.getDuration(), clone1.getDuration());
718         assertEquals(animator2.getDuration(), clone2.getDuration());
719         assertSame(animator1.getInterpolator(), clone1.getInterpolator());
720         assertSame(animator2.getInterpolator(), clone2.getInterpolator());
721     }
722 
723     /**
724      * Testing seeking in an AnimatorSet containing sequential animators.
725      */
726     @Test
testSeeking()727     public void testSeeking() throws Throwable {
728         final AnimatorSet set = new AnimatorSet();
729         final ValueAnimator a1 = ValueAnimator.ofFloat(0f, 150f);
730         a1.setDuration(150);
731         final ValueAnimator a2 = ValueAnimator.ofFloat(150f, 250f);
732         a2.setDuration(100);
733         final ValueAnimator a3 = ValueAnimator.ofFloat(250f, 300f);
734         a3.setDuration(50);
735 
736         a1.setInterpolator(null);
737         a2.setInterpolator(null);
738         a3.setInterpolator(null);
739 
740         set.playSequentially(a1, a2, a3);
741 
742         set.setCurrentPlayTime(100);
743         assertEquals(100f, (Float) a1.getAnimatedValue(), EPSILON);
744         assertEquals(150f, (Float) a2.getAnimatedValue(), EPSILON);
745         assertEquals(250f, (Float) a3.getAnimatedValue(), EPSILON);
746 
747         set.setCurrentPlayTime(280);
748         assertEquals(150f, (Float) a1.getAnimatedValue(), EPSILON);
749         assertEquals(250f, (Float) a2.getAnimatedValue(), EPSILON);
750         assertEquals(280f, (Float) a3.getAnimatedValue(), EPSILON);
751 
752         AnimatorListenerAdapter setListener = new AnimatorListenerAdapter() {
753             @Override
754             public void onAnimationEnd(Animator animation) {
755                 super.onAnimationEnd(animation);
756                 assertEquals(150f, (Float) a1.getAnimatedValue(), EPSILON);
757                 assertEquals(250f, (Float) a2.getAnimatedValue(), EPSILON);
758                 assertEquals(300f, (Float) a3.getAnimatedValue(), EPSILON);
759             }
760         };
761         AnimatorListenerAdapter mockListener = mock(AnimatorListenerAdapter.class);
762         set.addListener(setListener);
763         set.addListener(mockListener);
764         mActivityRule.runOnUiThread(() -> {
765             set.start();
766         });
767 
768         verify(mockListener, within(300)).onAnimationEnd(set, false);
769 
770         // Seek after a run to the middle-ish, and verify the first animator is at the end
771         // value and the 3rd at beginning value, and the 2nd animator is at the seeked value.
772         set.setCurrentPlayTime(200);
773         assertEquals(150f, (Float) a1.getAnimatedValue(), EPSILON);
774         assertEquals(200f, (Float) a2.getAnimatedValue(), EPSILON);
775         assertEquals(250f, (Float) a3.getAnimatedValue(), EPSILON);
776     }
777 
778     /**
779      * Testing seeking in an AnimatorSet containing infinite animators.
780      */
781     @Test
testSeekingInfinite()782     public void testSeekingInfinite() {
783         final AnimatorSet set = new AnimatorSet();
784         final ValueAnimator a1 = ValueAnimator.ofFloat(0f, 100f);
785         a1.setDuration(100);
786         final ValueAnimator a2 = ValueAnimator.ofFloat(100f, 200f);
787         a2.setDuration(100);
788         a2.setRepeatCount(ValueAnimator.INFINITE);
789         a2.setRepeatMode(ValueAnimator.RESTART);
790 
791         final ValueAnimator a3 = ValueAnimator.ofFloat(100f, 200f);
792         a3.setDuration(100);
793         a3.setRepeatCount(ValueAnimator.INFINITE);
794         a3.setRepeatMode(ValueAnimator.REVERSE);
795 
796         a1.setInterpolator(null);
797         a2.setInterpolator(null);
798         a3.setInterpolator(null);
799         set.play(a1).before(a2);
800         set.play(a1).before(a3);
801 
802         set.setCurrentPlayTime(50);
803         assertEquals(50f, (Float) a1.getAnimatedValue(), EPSILON);
804         assertEquals(100f, (Float) a2.getAnimatedValue(), EPSILON);
805         assertEquals(100f, (Float) a3.getAnimatedValue(), EPSILON);
806 
807         set.setCurrentPlayTime(100);
808         assertEquals(100f, (Float) a1.getAnimatedValue(), EPSILON);
809         assertEquals(100f, (Float) a2.getAnimatedValue(), EPSILON);
810         assertEquals(100f, (Float) a3.getAnimatedValue(), EPSILON);
811 
812         // Seek to the 1st iteration of the infinite repeat animators, and they should have the
813         // same value.
814         set.setCurrentPlayTime(180);
815         assertEquals(100f, (Float) a1.getAnimatedValue(), EPSILON);
816         assertEquals(180f, (Float) a2.getAnimatedValue(), EPSILON);
817         assertEquals(180f, (Float) a3.getAnimatedValue(), EPSILON);
818 
819         // Seek to the 2nd iteration of the infinite repeat animators, and they should have
820         // different values as they have different repeat mode.
821         set.setCurrentPlayTime(280);
822         assertEquals(100f, (Float) a1.getAnimatedValue(), EPSILON);
823         assertEquals(180f, (Float) a2.getAnimatedValue(), EPSILON);
824         assertEquals(120f, (Float) a3.getAnimatedValue(), EPSILON);
825 
826     }
827 
828     /**
829      * This test verifies that getCurrentPlayTime() returns the right value.
830      */
831     @Test
testGetCurrentPlayTime()832     public void testGetCurrentPlayTime() throws Throwable {
833         // Setup an AnimatorSet with start delay
834         final AnimatorSet set = new AnimatorSet();
835         final ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f).setDuration(300);
836         anim.addListener(new AnimatorListenerAdapter() {
837             @Override
838             public void onAnimationStart(Animator animation, boolean inReverse) {
839                 assertFalse(inReverse);
840                 assertEquals(200, set.getCurrentPlayTime());
841             }
842         });
843         set.play(anim);
844         set.setStartDelay(100);
845 
846         Animator.AnimatorListener setListener = mock(AnimatorListenerAdapter.class);
847         set.addListener(setListener);
848 
849         // Set a seek time and verify, before start
850         set.setCurrentPlayTime(20);
851         assertEquals(20, set.getCurrentPlayTime());
852 
853         // Now start() should start right away from the seeked position, skipping the delay.
854         mActivityRule.runOnUiThread(() -> {
855             set.setCurrentPlayTime(200);
856             set.start();
857             assertEquals(200, set.getCurrentPlayTime());
858         });
859 
860         // When animation is seeked to 200ms, it should take another 100ms to end.
861         verify(setListener, within(200)).onAnimationEnd(set, false);
862     }
863 
864     @Test
testNotifiesAfterEnd()865     public void testNotifiesAfterEnd() throws Throwable {
866         final ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
867         Animator.AnimatorListener listener = new AnimatorListenerAdapter() {
868             @Override
869             public void onAnimationStart(Animator animation) {
870                 assertTrue(animation.isStarted());
871                 assertTrue(animation.isRunning());
872             }
873 
874             @Override
875             public void onAnimationEnd(Animator animation) {
876                 assertFalse(animation.isRunning());
877                 assertFalse(animation.isStarted());
878                 super.onAnimationEnd(animation);
879             }
880         };
881         animator.addListener(listener);
882         final AnimatorSet animatorSet = new AnimatorSet();
883         animatorSet.playTogether(animator);
884         animatorSet.addListener(listener);
885         mActivityRule.runOnUiThread(() -> {
886             animatorSet.start();
887             animator.end();
888             assertFalse(animator.isStarted());
889         });
890     }
891 
892     /**
893      * Test that when a child animator is being manipulated outside of an AnimatorSet, by the time
894      * AnimatorSet starts, it will not be affected, and all the child animators would start at their
895      * scheduled start time.
896      */
897     @Test
testManipulateChildOutsideOfSet()898     public void testManipulateChildOutsideOfSet() throws Throwable {
899         final ValueAnimator fadeIn = ObjectAnimator.ofFloat(mActivity.view, View.ALPHA, 0f, 1f);
900         fadeIn.setDuration(200);
901         final ValueAnimator fadeOut = ObjectAnimator.ofFloat(mActivity.view, View.ALPHA, 1f, 0f);
902         fadeOut.setDuration(200);
903 
904         ValueAnimator.AnimatorUpdateListener listener = mock(
905                 ValueAnimator.AnimatorUpdateListener.class);
906         fadeIn.addUpdateListener(listener);
907 
908         AnimatorSet show = new AnimatorSet();
909         show.play(fadeIn);
910 
911         AnimatorSet hideNShow = new AnimatorSet();
912         hideNShow.play(fadeIn).after(fadeOut);
913 
914         mActivityRule.runOnUiThread(() ->
915                 show.start()
916         );
917 
918         verify(listener, timeout(100).atLeast(2)).onAnimationUpdate(fadeIn);
919 
920         AnimatorListenerAdapter adapter = mock(AnimatorListenerAdapter.class);
921         hideNShow.addListener(adapter);
922         // Start hideNShow after fadeIn is started for 100ms
923         mActivityRule.runOnUiThread(() ->
924                 hideNShow.start()
925         );
926 
927         verify(adapter, timeout(800)).onAnimationEnd(hideNShow, false);
928         // Now that the hideNShow finished we need to check whether the fadeIn animation ran again.
929         assertEquals(1f, mActivity.view.getAlpha(), 0);
930 
931     }
932 
933     /**
934      *
935      * This test verifies that custom ValueAnimators will be start()'ed in a set.
936      */
937     @Test
testChildAnimatorStartCalled()938     public void testChildAnimatorStartCalled() throws Throwable {
939         MyValueAnimator a1 = new MyValueAnimator();
940         MyValueAnimator a2 = new MyValueAnimator();
941         AnimatorSet set = new AnimatorSet();
942         set.playTogether(a1, a2);
943         mActivityRule.runOnUiThread(() -> {
944             set.start();
945             assertTrue(a1.mStartCalled);
946             assertTrue(a2.mStartCalled);
947         });
948     }
949 
950     @Test
seekSequentially()951     public void seekSequentially() {
952         AnimatorSet animatorSet = new AnimatorSet();
953         animatorSet.setStartDelay(10);
954         ValueAnimator animator1 = ValueAnimator.ofFloat(0f, 1f);
955         animator1.setInterpolator(null);
956         animator1.setStartDelay(5);
957         ValueAnimator animator2 = ValueAnimator.ofFloat(0f, 1f);
958         animator2.setInterpolator(null);
959         animator2.setStartDelay(5);
960         animatorSet.playSequentially(animator1, animator2);
961         animatorSet.setCurrentPlayTime(1);
962         assertEquals(1L, animatorSet.getCurrentPlayTime());
963         assertEquals(0f, (float) animator1.getAnimatedValue(), EPSILON);
964         assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON);
965         animatorSet.setCurrentPlayTime(15);
966         assertEquals(15L, animatorSet.getCurrentPlayTime());
967         assertEquals(0f, (float) animator1.getAnimatedValue(), EPSILON);
968         assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON);
969         animatorSet.setCurrentPlayTime(17);
970         assertEquals(17L, animatorSet.getCurrentPlayTime());
971         assertEquals(2f / 300f, (float) animator1.getAnimatedValue(), EPSILON);
972         assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON);
973         animatorSet.setCurrentPlayTime(316);
974         assertEquals(316, animatorSet.getCurrentPlayTime());
975         assertEquals(1f, (float) animator1.getAnimatedValue(), EPSILON);
976         assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON);
977         animatorSet.setCurrentPlayTime(320);
978         assertEquals(320, animatorSet.getCurrentPlayTime());
979         assertEquals(1f, (float) animator1.getAnimatedValue(), EPSILON);
980         assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON);
981         animatorSet.setCurrentPlayTime(321);
982         assertEquals(321, animatorSet.getCurrentPlayTime());
983         assertEquals(1f, (float) animator1.getAnimatedValue(), EPSILON);
984         assertEquals(1f / 300f, (float) animator2.getAnimatedValue(), EPSILON);
985         animatorSet.setCurrentPlayTime(320);
986         assertEquals(320, animatorSet.getCurrentPlayTime());
987         assertEquals(1f, (float) animator1.getAnimatedValue(), EPSILON);
988         assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON);
989         animatorSet.setCurrentPlayTime(314);
990         assertEquals(314, animatorSet.getCurrentPlayTime());
991         assertEquals(299f / 300f, (float) animator1.getAnimatedValue(), EPSILON);
992         assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON);
993     }
994 
995     @Test
seekSequentiallyWithRepeats()996     public void seekSequentiallyWithRepeats() {
997         AnimatorSet animatorSet = new AnimatorSet();
998         ValueAnimator animator1 = ValueAnimator.ofFloat(0f, 1f);
999         animator1.setInterpolator(null);
1000         animator1.setRepeatCount(1);
1001         ValueAnimator animator2 = ValueAnimator.ofFloat(0f, 1f);
1002         animator2.setInterpolator(null);
1003         animator2.setRepeatCount(ValueAnimator.INFINITE);
1004         animatorSet.playSequentially(animator1, animator2);
1005         animatorSet.setCurrentPlayTime(1);
1006         assertEquals(1L, animatorSet.getCurrentPlayTime());
1007         assertEquals(1f / 300f, (float) animator1.getAnimatedValue(), EPSILON);
1008         assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON);
1009         animatorSet.setCurrentPlayTime(301);
1010         assertEquals(301, animatorSet.getCurrentPlayTime());
1011         assertEquals(1f / 300f, (float) animator1.getAnimatedValue(), EPSILON);
1012         assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON);
1013         animatorSet.setCurrentPlayTime(699);
1014         assertEquals(699, animatorSet.getCurrentPlayTime());
1015         assertEquals(99f / 300f, (float) animator2.getAnimatedValue(), EPSILON);
1016         animatorSet.setCurrentPlayTime(601);
1017         assertEquals(601, animatorSet.getCurrentPlayTime());
1018         assertEquals(1f / 300f, (float) animator2.getAnimatedValue(), EPSILON);
1019         animatorSet.setCurrentPlayTime(599);
1020         assertEquals(599, animatorSet.getCurrentPlayTime());
1021         assertEquals(299f / 300f, (float) animator1.getAnimatedValue(), EPSILON);
1022         assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON);
1023     }
1024 
1025     @Test
seekReverse()1026     public void seekReverse() throws Throwable {
1027         AnimatorSet animatorSet = new AnimatorSet();
1028         animatorSet.setStartDelay(10);
1029         ValueAnimator animator1 = ValueAnimator.ofFloat(0f, 1f);
1030         animator1.setInterpolator(null);
1031         animator1.setStartDelay(5);
1032         ValueAnimator animator2 = ValueAnimator.ofFloat(0f, 1f);
1033         animator2.setInterpolator(null);
1034         animator2.setStartDelay(5);
1035         animatorSet.playSequentially(animator1, animator2);
1036         mActivityRule.runOnUiThread(() -> {
1037             animatorSet.reverse();
1038             animatorSet.pause();
1039             assertEquals(1f, (float) animator1.getAnimatedValue(), EPSILON);
1040             assertEquals(1f, (float) animator2.getAnimatedValue(), EPSILON);
1041             animatorSet.setCurrentPlayTime(1);
1042             assertEquals(1f, (float) animator1.getAnimatedValue(), EPSILON);
1043             assertEquals(299f / 300f, (float) animator2.getAnimatedValue(), EPSILON);
1044             animatorSet.setCurrentPlayTime(300);
1045             assertEquals(1f, (float) animator1.getAnimatedValue(), EPSILON);
1046             assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON);
1047             animatorSet.setCurrentPlayTime(305);
1048             assertEquals(1f, (float) animator1.getAnimatedValue(), EPSILON);
1049             assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON);
1050             animatorSet.setCurrentPlayTime(306);
1051             assertEquals(299f / 300f, (float) animator1.getAnimatedValue(), EPSILON);
1052             assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON);
1053             animatorSet.setCurrentPlayTime(604);
1054             assertEquals(1f / 300f, (float) animator1.getAnimatedValue(), EPSILON);
1055             assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON);
1056             animatorSet.setCurrentPlayTime(610);
1057             assertEquals(0f, (float) animator1.getAnimatedValue(), EPSILON);
1058             assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON);
1059             animatorSet.setCurrentPlayTime(604);
1060             assertEquals(1f / 300f, (float) animator1.getAnimatedValue(), EPSILON);
1061             assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON);
1062             animatorSet.setCurrentPlayTime(305);
1063             assertEquals(1f, (float) animator1.getAnimatedValue(), EPSILON);
1064             assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON);
1065         });
1066     }
1067 
1068     @Test
seekForwardOrder()1069     public void seekForwardOrder() {
1070         TargetObj target = new TargetObj();
1071         target.setVal(20f);
1072         ObjectAnimator animator1 = ObjectAnimator.ofFloat(target, "val", 0f, 100f);
1073         animator1.setInterpolator(null);
1074         ObjectAnimator animator2 = ObjectAnimator.ofFloat(target, "val", 100f, 0f);
1075         animator2.setInterpolator(null);
1076         AnimatorSet animatorSet = new AnimatorSet();
1077         animatorSet.playSequentially(animator1, animator2);
1078 
1079         animatorSet.setCurrentPlayTime(0);
1080         assertEquals(0f, target.value, EPSILON);
1081 
1082         animatorSet.setCurrentPlayTime(200);
1083         assertEquals(100f * 200f / 300f, target.value, EPSILON);
1084 
1085         animatorSet.setCurrentPlayTime(300);
1086         assertEquals(100f, target.value, EPSILON);
1087 
1088         animatorSet.setCurrentPlayTime(350);
1089         assertEquals(100f * 250f / 300f, target.value, EPSILON);
1090 
1091         animatorSet.setCurrentPlayTime(600);
1092         assertEquals(0f, target.value, EPSILON);
1093 
1094         animatorSet.setCurrentPlayTime(250);
1095         assertEquals(100f * 250f / 300f, target.value, EPSILON);
1096 
1097         animatorSet.setCurrentPlayTime(0);
1098         assertEquals(0f, target.value, EPSILON);
1099     }
1100 
1101     @Test
seekBackwardOrder()1102     public void seekBackwardOrder() throws Throwable {
1103         TargetObj target = new TargetObj();
1104         target.setVal(20f);
1105         ObjectAnimator animator1 = ObjectAnimator.ofFloat(target, "val", 0f, 100f);
1106         animator1.setInterpolator(null);
1107         ObjectAnimator animator2 = ObjectAnimator.ofFloat(target, "val", 100f, 0f);
1108         animator2.setInterpolator(null);
1109         AnimatorSet animatorSet = new AnimatorSet();
1110         animatorSet.playSequentially(animator1, animator2);
1111 
1112         mActivityRule.runOnUiThread(() -> {
1113             animatorSet.reverse();
1114             animatorSet.pause();
1115 
1116             animatorSet.setCurrentPlayTime(0);
1117             assertEquals(0f, target.value, EPSILON);
1118 
1119             animatorSet.setCurrentPlayTime(200);
1120             assertEquals(100f * 200f / 300f, target.value, EPSILON);
1121 
1122             animatorSet.setCurrentPlayTime(300);
1123             assertEquals(100f, target.value, EPSILON);
1124 
1125             animatorSet.setCurrentPlayTime(350);
1126             assertEquals(100f * 250f / 300f, target.value, EPSILON);
1127 
1128             animatorSet.setCurrentPlayTime(600);
1129             assertEquals(0f, target.value, EPSILON);
1130 
1131             animatorSet.setCurrentPlayTime(250);
1132             assertEquals(100f * 250f / 300f, target.value, EPSILON);
1133 
1134             animatorSet.setCurrentPlayTime(0);
1135             assertEquals(0f, target.value, EPSILON);
1136         });
1137     }
1138 
1139     @Test
seekNestedSets()1140     public void seekNestedSets() {
1141         TargetObj target = new TargetObj();
1142         target.setVal(20f);
1143         ObjectAnimator animator1 = ObjectAnimator.ofFloat(target, "val", 0f, 100f);
1144         animator1.setInterpolator(null);
1145         ObjectAnimator animator2 = ObjectAnimator.ofFloat(target, "val", 100f, 0f);
1146         animator2.setInterpolator(null);
1147         AnimatorSet animatorSet1 = new AnimatorSet();
1148         animatorSet1.playSequentially(animator1, animator2);
1149         ValueAnimator animator3 = ValueAnimator.ofFloat(0f, 1f);
1150         animator3.setInterpolator(null);
1151         animator3.setStartDelay(100);
1152         AnimatorSet animatorSet = new AnimatorSet();
1153         animatorSet.playTogether(animatorSet1, animator3);
1154 
1155         animatorSet.setCurrentPlayTime(0);
1156         assertEquals(0f, target.value, EPSILON);
1157         assertEquals(0f, (float) animator3.getAnimatedValue(), EPSILON);
1158 
1159         animatorSet.setCurrentPlayTime(200);
1160         assertEquals(100f * 200f / 300f, target.value, EPSILON);
1161         assertEquals(100f / 300f, (float) animator3.getAnimatedValue(), EPSILON);
1162 
1163         animatorSet.setCurrentPlayTime(300);
1164         assertEquals(100f, target.value, EPSILON);
1165         assertEquals(200f / 300f, (float) animator3.getAnimatedValue(), EPSILON);
1166 
1167         animatorSet.setCurrentPlayTime(350);
1168         assertEquals(100f * 250f / 300f, target.value, EPSILON);
1169         assertEquals(250f / 300f, (float) animator3.getAnimatedValue(), EPSILON);
1170 
1171         animatorSet.setCurrentPlayTime(600);
1172         assertEquals(0f, target.value, EPSILON);
1173         assertEquals(1f, (float) animator3.getAnimatedValue(), EPSILON);
1174 
1175         animatorSet.setCurrentPlayTime(250);
1176         assertEquals(100f * 250f / 300f, target.value, EPSILON);
1177         assertEquals(150f / 300f, (float) animator3.getAnimatedValue(), EPSILON);
1178 
1179         animatorSet.setCurrentPlayTime(100);
1180         assertEquals(100f * 100f / 300f, target.value, EPSILON);
1181         assertEquals(0f, (float) animator3.getAnimatedValue(), EPSILON);
1182 
1183         animatorSet.setCurrentPlayTime(0);
1184         assertEquals(0f, target.value, EPSILON);
1185         assertEquals(0f, (float) animator3.getAnimatedValue(), EPSILON);
1186     }
1187 
1188     @Test
seekWithNestedAnimatorSetsAndDelays()1189     public void seekWithNestedAnimatorSetsAndDelays() {
1190         AnimatorSet animatorSet1 = new AnimatorSet();
1191         animatorSet1.setStartDelay(100);
1192         ValueAnimator animator1 = ValueAnimator.ofFloat(0f, 100f);
1193         animator1.setInterpolator(null);
1194         animator1.setStartDelay(200);
1195         animatorSet1.play(animator1);
1196         AnimatorSet animatorSet2 = new AnimatorSet();
1197         animatorSet2.setStartDelay(400);
1198         animatorSet2.play(animatorSet1);
1199         AnimatorSet animatorSet3 = new AnimatorSet();
1200         animatorSet3.play(animatorSet2);
1201 
1202         animatorSet3.setCurrentPlayTime(0);
1203         assertEquals(0f, (float) animator1.getAnimatedValue(), EPSILON);
1204         animatorSet3.setCurrentPlayTime(400);
1205         assertEquals(0f, (float) animator1.getAnimatedValue(), EPSILON);
1206         animatorSet3.setCurrentPlayTime(500);
1207         assertEquals(0f, (float) animator1.getAnimatedValue(), EPSILON);
1208         animatorSet3.setCurrentPlayTime(700);
1209         assertEquals(0f, (float) animator1.getAnimatedValue(), EPSILON);
1210         animatorSet3.setCurrentPlayTime(850);
1211         assertEquals(50f, (float) animator1.getAnimatedValue(), EPSILON);
1212         animatorSet3.setCurrentPlayTime(1000);
1213         assertEquals(100f, (float) animator1.getAnimatedValue(), EPSILON);
1214     }
1215 
1216     @Test
seekReversedWithNestedAnimatorSetsAndDelays()1217     public void seekReversedWithNestedAnimatorSetsAndDelays() throws Throwable {
1218         AnimatorSet animatorSet1 = new AnimatorSet();
1219         animatorSet1.setStartDelay(100);
1220         ValueAnimator animator1 = ValueAnimator.ofFloat(0f, 100f);
1221         animator1.setInterpolator(null);
1222         animator1.setStartDelay(200);
1223         animatorSet1.play(animator1);
1224         AnimatorSet animatorSet2 = new AnimatorSet();
1225         animatorSet2.setStartDelay(400);
1226         animatorSet2.play(animatorSet1);
1227         AnimatorSet animatorSet3 = new AnimatorSet();
1228         animatorSet3.play(animatorSet2);
1229 
1230         mActivityRule.runOnUiThread(() -> {
1231             animatorSet3.reverse();
1232             animatorSet3.pause();
1233             animatorSet3.setCurrentPlayTime(0);
1234             assertEquals(100f, (float) animator1.getAnimatedValue(), EPSILON);
1235             animatorSet3.setCurrentPlayTime(150);
1236             assertEquals(50f, (float) animator1.getAnimatedValue(), EPSILON);
1237             animatorSet3.setCurrentPlayTime(300);
1238             assertEquals(0f, (float) animator1.getAnimatedValue(), EPSILON);
1239             animatorSet3.setCurrentPlayTime(500);
1240             assertEquals(0f, (float) animator1.getAnimatedValue(), EPSILON);
1241             animatorSet3.setCurrentPlayTime(600);
1242             assertEquals(0f, (float) animator1.getAnimatedValue(), EPSILON);
1243             animatorSet3.setCurrentPlayTime(1000);
1244             assertEquals(0f, (float) animator1.getAnimatedValue(), EPSILON);
1245         });
1246     }
1247 
1248     /**
1249      * This test sets up an AnimatorSet that contains two sequential animations. The first animation
1250      * is infinite, the second animation therefore has an infinite start time. This test verifies
1251      * that the infinite start time is handled correctly.
1252      */
1253     @Test
testInfiniteStartTime()1254     public void testInfiniteStartTime() throws Throwable {
1255         ValueAnimator a1 = ValueAnimator.ofFloat(0f, 1f);
1256         a1.setRepeatCount(ValueAnimator.INFINITE);
1257         ValueAnimator a2 = ValueAnimator.ofFloat(0f, 1f);
1258 
1259         AnimatorSet set = new AnimatorSet();
1260         set.playSequentially(a1, a2);
1261 
1262         mActivityRule.runOnUiThread(() -> {
1263             set.start();
1264         });
1265 
1266         assertEquals(Animator.DURATION_INFINITE, set.getTotalDuration());
1267 
1268         mActivityRule.runOnUiThread(() -> {
1269             set.end();
1270         });
1271     }
1272 
1273     @Test
childListenersCalledWhilePaused()1274     public void childListenersCalledWhilePaused() throws Throwable {
1275         AnimationCountListener setListener1 = new AnimationCountListener();
1276         AnimationCountListener setListener2 = new AnimationCountListener();
1277         AnimatorSet animatorSet1 = new AnimatorSet();
1278         animatorSet1.addListener(setListener1);
1279         AnimatorSet animatorSet2 = new AnimatorSet();
1280         animatorSet2.addListener(setListener2);
1281         animatorSet2.setStartDelay(100);
1282         animatorSet1.play(animatorSet2);
1283 
1284         AnimatorSet animatorSet3 = new AnimatorSet();
1285         animatorSet2.play(animatorSet3);
1286         AnimationCountListener setListener3 = new AnimationCountListener();
1287         animatorSet3.addListener(setListener3);
1288 
1289         AnimationCountListener valueListener = new AnimationCountListener();
1290         ValueAnimator animator = ValueAnimator.ofFloat(0f, 100f);
1291         animator.addListener(valueListener);
1292         animator.setStartDelay(50);
1293         animatorSet3.play(animator);
1294 
1295         mActivityRule.runOnUiThread(() -> {
1296             animatorSet1.start();
1297             // Just starting should trigger the starting animators
1298             setListener1.assertListenerCount(1, 0, 0, 0);
1299             setListener2.assertListenerCount(1, 0, 0, 0);
1300             setListener3.assertListenerCount(0, 0, 0, 0);
1301             valueListener.assertListenerCount(0, 0, 0, 0);
1302 
1303             animatorSet1.pause();
1304 
1305             // Setting the play time shouldn't trigger any more animators
1306             animatorSet1.setCurrentPlayTime(0);
1307             setListener1.assertListenerCount(1, 0, 0, 0);
1308             setListener2.assertListenerCount(1, 0, 0, 0);
1309             setListener3.assertListenerCount(0, 0, 0, 0);
1310             valueListener.assertListenerCount(0, 0, 0, 0);
1311 
1312             // We've passed the start delay, so other animators should start
1313             animatorSet1.setCurrentPlayTime(100);
1314             setListener1.assertListenerCount(1, 0, 0, 0);
1315             setListener2.assertListenerCount(1, 0, 0, 0);
1316             setListener3.assertListenerCount(1, 0, 0, 0);
1317             valueListener.assertListenerCount(1, 0, 0, 0);
1318 
1319             // Reached the end of the animators, so all should end in the forward direction.
1320             animatorSet1.setCurrentPlayTime(450);
1321             setListener1.assertListenerCount(1, 0, 1, 0);
1322             setListener2.assertListenerCount(1, 0, 1, 0);
1323             setListener3.assertListenerCount(1, 0, 1, 0);
1324             valueListener.assertListenerCount(1, 0, 1, 0);
1325 
1326             // Go back towards the start should cause the animators to start in reverse
1327             animatorSet1.setCurrentPlayTime(101);
1328             setListener1.assertListenerCount(1, 1, 1, 0);
1329             setListener2.assertListenerCount(1, 1, 1, 0);
1330             setListener3.assertListenerCount(1, 1, 1, 0);
1331             valueListener.assertListenerCount(1, 1, 1, 0);
1332 
1333             // Now we've reached the start delay, so some animators finish
1334             animatorSet1.setCurrentPlayTime(100);
1335             setListener1.assertListenerCount(1, 1, 1, 0);
1336             setListener2.assertListenerCount(1, 1, 1, 0);
1337             setListener3.assertListenerCount(1, 1, 1, 1);
1338             valueListener.assertListenerCount(1, 1, 1, 1);
1339 
1340             // Now we're back at the beginning, so all animators will finish in reverse
1341             animatorSet1.setCurrentPlayTime(0);
1342             setListener1.assertListenerCount(1, 1, 1, 1);
1343             setListener2.assertListenerCount(1, 1, 1, 1);
1344             setListener3.assertListenerCount(1, 1, 1, 1);
1345             valueListener.assertListenerCount(1, 1, 1, 1);
1346 
1347             // Go forward to the middle, we'll have another start in the forward direction
1348             animatorSet1.setCurrentPlayTime(300);
1349             setListener1.assertListenerCount(2, 1, 1, 1);
1350             setListener2.assertListenerCount(2, 1, 1, 1);
1351             setListener3.assertListenerCount(2, 1, 1, 1);
1352             valueListener.assertListenerCount(2, 1, 1, 1);
1353 
1354             // When we go back, it should end in the reverse direction
1355             animatorSet1.setCurrentPlayTime(0);
1356             setListener1.assertListenerCount(2, 1, 1, 2);
1357             setListener2.assertListenerCount(2, 1, 1, 2);
1358             setListener3.assertListenerCount(2, 1, 1, 2);
1359             valueListener.assertListenerCount(2, 1, 1, 2);
1360         });
1361     }
1362 
1363     @Test
childListenersCalledReversed()1364     public void childListenersCalledReversed() throws Throwable {
1365         AnimationCountListener setListener = new AnimationCountListener();
1366         AnimatorSet animatorSet = new AnimatorSet();
1367         animatorSet.addListener(setListener);
1368 
1369         AnimationCountListener valueListener = new AnimationCountListener();
1370         ValueAnimator animator = ValueAnimator.ofFloat(0f, 100f);
1371         animator.addListener(valueListener);
1372         animator.setRepeatCount(1);
1373         animator.setStartDelay(50);
1374         animatorSet.play(animator);
1375 
1376         mActivityRule.runOnUiThread(() -> {
1377             animatorSet.reverse();
1378             // Just starting should trigger the starting animators
1379             setListener.assertListenerCount(0, 1, 0, 0);
1380             valueListener.assertListenerCount(0, 1, 0, 0);
1381 
1382             // Setting the play time shouldn't trigger any more animators
1383             animatorSet.setCurrentPlayTime(0);
1384             setListener.assertListenerCount(0, 1, 0, 0);
1385             valueListener.assertListenerCount(0, 1, 0, 0);
1386 
1387             // Middle of the ValueAnimator
1388             animatorSet.setCurrentPlayTime(300);
1389             setListener.assertListenerCount(0, 1, 0, 0);
1390             valueListener.assertListenerCount(0, 1, 0, 0);
1391 
1392             // Reached the end of the ValueAnimator, but not the start delay
1393             animatorSet.setCurrentPlayTime(600);
1394             setListener.assertListenerCount(0, 1, 0, 0);
1395             valueListener.assertListenerCount(0, 1, 0, 0);
1396 
1397             // End of the startDelay
1398             animatorSet.setCurrentPlayTime(650);
1399             setListener.assertListenerCount(0, 1, 0, 1);
1400             valueListener.assertListenerCount(0, 1, 0, 1);
1401         });
1402     }
1403 
1404     @Test
childListenersCalledWithNoStart()1405     public void childListenersCalledWithNoStart() {
1406         AnimationCountListener setListener1 = new AnimationCountListener();
1407         AnimationCountListener setListener2 = new AnimationCountListener();
1408         AnimatorSet animatorSet1 = new AnimatorSet();
1409         animatorSet1.addListener(setListener1);
1410         AnimatorSet animatorSet2 = new AnimatorSet();
1411         animatorSet2.addListener(setListener2);
1412         animatorSet2.setStartDelay(100);
1413         animatorSet1.play(animatorSet2);
1414 
1415         AnimatorSet animatorSet3 = new AnimatorSet();
1416         animatorSet2.play(animatorSet3);
1417         AnimationCountListener setListener3 = new AnimationCountListener();
1418         animatorSet3.addListener(setListener3);
1419 
1420         AnimationCountListener valueListener = new AnimationCountListener();
1421         ValueAnimator animator = ValueAnimator.ofFloat(0f, 100f);
1422         animator.addListener(valueListener);
1423         animator.setStartDelay(50);
1424         animatorSet3.play(animator);
1425 
1426         // Nothing is started, so no listeners should be called
1427         setListener1.assertListenerCount(0, 0, 0, 0);
1428         setListener2.assertListenerCount(0, 0, 0, 0);
1429         setListener3.assertListenerCount(0, 0, 0, 0);
1430         valueListener.assertListenerCount(0, 0, 0, 0);
1431 
1432         // Just setting the play time should start some listeners
1433         animatorSet1.setCurrentPlayTime(0);
1434 
1435         setListener1.assertListenerCount(1, 0, 0, 0);
1436         setListener2.assertListenerCount(1, 0, 0, 0);
1437         setListener3.assertListenerCount(0, 0, 0, 0);
1438         valueListener.assertListenerCount(0, 0, 0, 0);
1439 
1440         // We've passed the start delay, so other animators should start
1441         animatorSet1.setCurrentPlayTime(100);
1442         setListener1.assertListenerCount(1, 0, 0, 0);
1443         setListener2.assertListenerCount(1, 0, 0, 0);
1444         setListener3.assertListenerCount(1, 0, 0, 0);
1445         valueListener.assertListenerCount(1, 0, 0, 0);
1446 
1447         // Reached the end of the animators, so all should end in the forward direction.
1448         animatorSet1.setCurrentPlayTime(450);
1449         setListener1.assertListenerCount(1, 0, 1, 0);
1450         setListener2.assertListenerCount(1, 0, 1, 0);
1451         setListener3.assertListenerCount(1, 0, 1, 0);
1452         valueListener.assertListenerCount(1, 0, 1, 0);
1453 
1454         // Go back towards the start should cause the animators to start in reverse
1455         animatorSet1.setCurrentPlayTime(101);
1456         setListener1.assertListenerCount(1, 1, 1, 0);
1457         setListener2.assertListenerCount(1, 1, 1, 0);
1458         setListener3.assertListenerCount(1, 1, 1, 0);
1459         valueListener.assertListenerCount(1, 1, 1, 0);
1460 
1461         // Now we've reached the start delay, so some animators finish
1462         animatorSet1.setCurrentPlayTime(100);
1463         setListener1.assertListenerCount(1, 1, 1, 0);
1464         setListener2.assertListenerCount(1, 1, 1, 0);
1465         setListener3.assertListenerCount(1, 1, 1, 1);
1466         valueListener.assertListenerCount(1, 1, 1, 1);
1467 
1468         // Now we're back at the beginning, so all animators will finish in reverse
1469         animatorSet1.setCurrentPlayTime(0);
1470         setListener1.assertListenerCount(1, 1, 1, 1);
1471         setListener2.assertListenerCount(1, 1, 1, 1);
1472         setListener3.assertListenerCount(1, 1, 1, 1);
1473         valueListener.assertListenerCount(1, 1, 1, 1);
1474 
1475         // Go forward to the middle, we'll have another start in the forward direction
1476         animatorSet1.setCurrentPlayTime(300);
1477         setListener1.assertListenerCount(2, 1, 1, 1);
1478         setListener2.assertListenerCount(2, 1, 1, 1);
1479         setListener3.assertListenerCount(2, 1, 1, 1);
1480         valueListener.assertListenerCount(2, 1, 1, 1);
1481 
1482         // When we go back, it should end in the reverse direction
1483         animatorSet1.setCurrentPlayTime(0);
1484         setListener1.assertListenerCount(2, 1, 1, 2);
1485         setListener2.assertListenerCount(2, 1, 1, 2);
1486         setListener3.assertListenerCount(2, 1, 1, 2);
1487         valueListener.assertListenerCount(2, 1, 1, 2);
1488     }
1489 
1490     static class AnimationCountListener implements Animator.AnimatorListener {
1491         public int startForward;
1492         public int startReversed;
1493         public int endForward;
1494         public int endReversed;
1495 
1496         @Override
onAnimationStart(@onNull Animator animation, boolean isReverse)1497         public void onAnimationStart(@NonNull Animator animation, boolean isReverse) {
1498             if (isReverse) {
1499                 startReversed++;
1500             } else {
1501                 startForward++;
1502             }
1503         }
1504 
1505         @Override
onAnimationEnd(@onNull Animator animation, boolean isReverse)1506         public void onAnimationEnd(@NonNull Animator animation, boolean isReverse) {
1507             if (isReverse) {
1508                 endReversed++;
1509             } else {
1510                 endForward++;
1511             }
1512         }
1513 
1514         @Override
onAnimationStart(@onNull Animator animation)1515         public void onAnimationStart(@NonNull Animator animation) {
1516         }
1517 
1518         @Override
onAnimationEnd(@onNull Animator animation)1519         public void onAnimationEnd(@NonNull Animator animation) {
1520         }
1521 
1522         @Override
onAnimationCancel(@onNull Animator animation)1523         public void onAnimationCancel(@NonNull Animator animation) {
1524         }
1525 
1526         @Override
onAnimationRepeat(@onNull Animator animation)1527         public void onAnimationRepeat(@NonNull Animator animation) {
1528         }
1529 
assertListenerCount( int startForward, int startReversed, int endForward, int endReversed )1530         public void assertListenerCount(
1531                 int startForward,
1532                 int startReversed,
1533                 int endForward,
1534                 int endReversed
1535         ) {
1536             assertEquals(startForward, this.startForward);
1537             assertEquals(startReversed, this.startReversed);
1538             assertEquals(endForward, this.endForward);
1539             assertEquals(endReversed, this.endReversed);
1540         }
1541     }
1542 
1543     static class TargetObj {
1544         public float value = 0;
1545 
setVal(float value)1546         public void setVal(float value) {
1547             this.value = value;
1548         }
1549 
getVal()1550         public float getVal() {
1551             return value;
1552         }
1553     }
1554 
1555     class AnimateObject {
1556         int x = 1;
1557         int y = 2;
1558     }
1559 
1560     static class MyListener extends AnimatorListenerAdapter {
1561         boolean mStartIsCalled = false;
1562         boolean mEndIsCalled = false;
1563 
onAnimationStart(Animator animation)1564         public void onAnimationStart(Animator animation) {
1565             mStartIsCalled = true;
1566         }
1567 
onAnimationEnd(Animator animation)1568         public void onAnimationEnd(Animator animation) {
1569             mEndIsCalled = true;
1570         }
1571     }
1572 
1573     static class MyValueAnimator extends ValueAnimator {
1574         boolean mStartCalled = false;
1575         @Override
start()1576         public void start() {
1577             // Do not call super intentionally.
1578             mStartCalled = true;
1579         }
1580     }
1581 }
1582