1 /*
2  * Copyright 2018 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 
17 package androidx.core.animation;
18 
19 import static androidx.core.animation.AnimatorSetTest.AnimEvent.EventType.END;
20 import static androidx.core.animation.AnimatorSetTest.AnimEvent.EventType.START;
21 
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertFalse;
24 import static org.junit.Assert.assertSame;
25 import static org.junit.Assert.assertTrue;
26 
27 import android.util.Property;
28 
29 import androidx.test.annotation.UiThreadTest;
30 import androidx.test.ext.junit.runners.AndroidJUnit4;
31 import androidx.test.filters.SmallTest;
32 
33 import org.jspecify.annotations.NonNull;
34 import org.junit.After;
35 import org.junit.Before;
36 import org.junit.ClassRule;
37 import org.junit.Test;
38 import org.junit.runner.RunWith;
39 
40 import java.util.ArrayList;
41 import java.util.List;
42 import java.util.concurrent.atomic.AtomicLong;
43 
44 @SmallTest
45 @RunWith(AndroidJUnit4.class)
46 public class AnimatorSetTest {
47     private AnimatorSet mAnimatorSet;
48     private float mPreviousDurationScale = 1.0f;
49     private ValueAnimator mAnim1;
50     private ValueAnimator mAnim2;
51     private static final float EPSILON = 0.001f;
52     enum PlayOrder {
53         SEQUENTIAL,
54         TOGETHER
55     }
56 
57     @Before
setup()58     public void setup() {
59         mPreviousDurationScale = ValueAnimator.getDurationScale();
60         ValueAnimator.setDurationScale(1.0f);
61         mAnim1 = ValueAnimator.ofFloat(0f, 100f);
62         mAnim2 = ValueAnimator.ofInt(100, 200);
63     }
64 
65     @After
tearDown()66     public void tearDown() {
67         ValueAnimator.setDurationScale(mPreviousDurationScale);
68     }
69 
70     @ClassRule
71     public static AnimatorTestRule sAnimatorTestRule = new AnimatorTestRule();
72 
73     @UiThreadTest
74     @Test
testPlaySequentially()75     public void testPlaySequentially() {
76 
77         List<Animator> animators = new ArrayList<Animator>();
78         animators.add(mAnim1);
79         animators.add(mAnim2);
80         mAnimatorSet = new AnimatorSet();
81         mAnimatorSet.playSequentially(animators);
82         verifyPlayOrder(mAnimatorSet, new Animator[] {mAnim1, mAnim2}, PlayOrder.SEQUENTIAL);
83 
84         AnimatorSet set = new AnimatorSet();
85         set.playSequentially(mAnim1, mAnim2);
86         verifyPlayOrder(set, new Animator[] {mAnim1, mAnim2}, PlayOrder.SEQUENTIAL);
87     }
88 
89     @UiThreadTest
90     @Test
testPlayTogether()91     public void testPlayTogether() {
92 
93         List<Animator> animators = new ArrayList<Animator>();
94         animators.add(mAnim1);
95         animators.add(mAnim2);
96         mAnimatorSet = new AnimatorSet();
97         mAnimatorSet.playTogether(animators);
98         verifyPlayOrder(mAnimatorSet, new Animator[] {mAnim1, mAnim2}, PlayOrder.TOGETHER);
99 
100         AnimatorSet set = new AnimatorSet();
101         set.playTogether(mAnim1, mAnim2);
102         verifyPlayOrder(set, new Animator[] {mAnim1, mAnim2}, PlayOrder.TOGETHER);
103     }
104 
105     /**
106      * Start the animator, and verify the animators are played sequentially in the order that is
107      * defined in the array.
108      *
109      * @param set AnimatorSet to be started and verified
110      * @param animators animators that we put in the AnimatorSet, in the order that they'll play
111      */
verifyPlayOrder(final AnimatorSet set, Animator[] animators, PlayOrder playOrder)112     private void verifyPlayOrder(final AnimatorSet set, Animator[] animators, PlayOrder playOrder) {
113         ArrayList<AnimEvent> animEvents = registerAnimatorsForEvents(animators);
114 
115         set.start();
116 
117         sAnimatorTestRule.advanceTimeBy(set.getStartDelay());
118         for (int i = 0; i < animators.length; i++) {
119             sAnimatorTestRule.advanceTimeBy(animators[i].getTotalDuration());
120         }
121 
122         // All animations should finish by now
123         int animatorNum = animators.length;
124         assertEquals(animatorNum * 2, animEvents.size());
125 
126         if (playOrder == PlayOrder.SEQUENTIAL) {
127             for (int i = 0; i < animatorNum; i++) {
128                 assertEquals(START, animEvents.get(i * 2).mType);
129                 assertEquals(animators[i], animEvents.get(i * 2).mAnim);
130                 assertEquals(END, animEvents.get(i * 2 + 1).mType);
131                 assertEquals(animators[i], animEvents.get(i * 2 + 1).mAnim);
132             }
133         } else {
134             for (int i = 0; i < animatorNum; i++) {
135                 assertEquals(START, animEvents.get(i).mType);
136                 assertEquals(animators[i], animEvents.get(i).mAnim);
137             }
138         }
139     }
140 
registerAnimatorsForEvents(Animator[] animators)141     private ArrayList<AnimEvent> registerAnimatorsForEvents(Animator[] animators) {
142         final ArrayList<AnimEvent> animEvents = new ArrayList<>();
143         Animator.AnimatorListener listener = new Animator.AnimatorListener() {
144             @Override
145             public void onAnimationStart(@NonNull Animator animation) {
146                 animEvents.add(new AnimEvent(START, animation));
147             }
148 
149             @Override
150             public void onAnimationEnd(@NonNull Animator animation) {
151                 animEvents.add(new AnimEvent(END, animation));
152             }
153 
154             @Override
155             public void onAnimationCancel(@NonNull Animator animation) {
156 
157             }
158 
159             @Override
160             public void onAnimationRepeat(@NonNull Animator animation) {
161 
162             }
163         };
164 
165         for (int i = 0; i < animators.length; i++) {
166             animators[i].removeListener(listener);
167             animators[i].addListener(listener);
168         }
169         return animEvents;
170     }
171 
172     @UiThreadTest
173     @Test
testPlayBeforeAfter()174     public void testPlayBeforeAfter() {
175 
176         final ValueAnimator anim3 = ValueAnimator.ofFloat(200f, 300f);
177 
178         AnimatorSet set = new AnimatorSet();
179         set.play(mAnim1).before(mAnim2).after(anim3);
180 
181         verifyPlayOrder(set, new Animator[] {anim3, mAnim1, mAnim2}, PlayOrder.SEQUENTIAL);
182     }
183 
184     @UiThreadTest
185     @Test
testListenerCallbackOnEmptySet()186     public void testListenerCallbackOnEmptySet() {
187         // Create an AnimatorSet that only contains one empty AnimatorSet, and checks the callback
188         // sequence by checking the time stamps of the callbacks.
189         final AnimatorSet emptySet = new AnimatorSet();
190         final AnimatorSet set = new AnimatorSet();
191         set.play(emptySet);
192 
193 
194         ArrayList<AnimEvent> animEvents = registerAnimatorsForEvents(
195                 new Animator[] {emptySet, set});
196         set.start();
197         sAnimatorTestRule.advanceTimeBy(10);
198 
199         // Check callback sequence via Animator Events
200         assertEquals(animEvents.get(0).mAnim, set);
201         assertEquals(animEvents.get(0).mType, START);
202         assertEquals(animEvents.get(1).mAnim, emptySet);
203         assertEquals(animEvents.get(1).mType, START);
204 
205         assertEquals(animEvents.get(2).mAnim, emptySet);
206         assertEquals(animEvents.get(2).mType, END);
207         assertEquals(animEvents.get(3).mAnim, set);
208         assertEquals(animEvents.get(3).mType, END);
209     }
210 
211     @UiThreadTest
212     @Test
testPause()213     public void testPause() {
214         final ValueAnimator anim = ValueAnimator.ofFloat(0f, 1000f);
215         anim.setDuration(1000L);
216         anim.setInterpolator(new LinearInterpolator());
217         final AnimatorSet set = new AnimatorSet();
218         set.playTogether(anim);
219 
220         set.start();
221         sAnimatorTestRule.advanceTimeBy(300);
222         assertEquals(300L, set.getCurrentPlayTime());
223         assertEquals(300f, (float) anim.getAnimatedValue(), EPSILON);
224 
225         set.pause();
226         sAnimatorTestRule.advanceTimeBy(300);
227         assertEquals(300L, set.getCurrentPlayTime());
228         assertEquals(300f, (float) anim.getAnimatedValue(), EPSILON);
229 
230         set.resume();
231         sAnimatorTestRule.advanceTimeBy(300);
232         assertEquals(600L, set.getCurrentPlayTime());
233         assertEquals(600f, (float) anim.getAnimatedValue(), EPSILON);
234     }
235 
236     @UiThreadTest
237     @Test
testPauseAndResume()238     public void testPauseAndResume() {
239         final AnimatorSet set = new AnimatorSet();
240         set.playTogether(mAnim1, mAnim2);
241 
242         set.start();
243         sAnimatorTestRule.advanceTimeBy(0);
244         set.pause();
245         assertTrue(set.isPaused());
246         sAnimatorTestRule.advanceTimeBy(5);
247 
248         // After 10s, set is still not yet finished.
249         sAnimatorTestRule.advanceTimeBy(10000);
250         assertTrue(set.isStarted());
251         assertTrue(set.isPaused());
252         set.resume();
253 
254         sAnimatorTestRule.advanceTimeBy(5);
255         assertTrue(set.isStarted());
256         assertFalse(set.isPaused());
257 
258         sAnimatorTestRule.advanceTimeBy(10000);
259         assertFalse(set.isStarted());
260         assertFalse(set.isPaused());
261     }
262 
263     @UiThreadTest
264     @Test
testPauseBeforeStart()265     public void testPauseBeforeStart() {
266         final AnimatorSet set = new AnimatorSet();
267         set.playSequentially(mAnim1, mAnim2);
268 
269         set.pause();
270         // Verify that pause should have no effect on a not-yet-started animator.
271         assertFalse(set.isPaused());
272         set.start();
273         sAnimatorTestRule.advanceTimeBy(0);
274         assertTrue(set.isStarted());
275 
276         sAnimatorTestRule.advanceTimeBy(set.getTotalDuration());
277         assertFalse(set.isStarted());
278     }
279 
280     @UiThreadTest
281     @Test
testPauseRewindResume()282     public void testPauseRewindResume() {
283         final AnimatorSet set = new AnimatorSet();
284         final ValueAnimator a1 = ValueAnimator.ofFloat(0f, 1000f);
285         a1.setDuration(1000);
286         final ValueAnimator a2 = ValueAnimator.ofInt(0, 1000);
287         a2.setDuration(1000);
288         set.playSequentially(a1, a2);
289         set.setInterpolator(new LinearInterpolator());
290 
291         assertEquals(2000L, set.getTotalDuration());
292         set.start();
293         sAnimatorTestRule.advanceTimeBy(1500L);
294         assertEquals(1000f, (float) a1.getAnimatedValue(), EPSILON);
295         assertEquals(500, (int) a2.getAnimatedValue());
296 
297         set.pause();
298         set.setCurrentPlayTime(500L);
299         assertEquals(500f, (float) a1.getAnimatedValue(), EPSILON);
300         assertEquals(0, (int) a2.getAnimatedValue());
301 
302         set.resume();
303         sAnimatorTestRule.advanceTimeBy(250L);
304         assertEquals(750f, (float) a1.getAnimatedValue(), EPSILON);
305         assertEquals(0, (int) a2.getAnimatedValue());
306 
307         sAnimatorTestRule.advanceTimeBy(750L);
308         assertEquals(1000f, (float) a1.getAnimatedValue(), EPSILON);
309         assertEquals(500, (int) a2.getAnimatedValue());
310     }
311 
312     @UiThreadTest
313     @Test
testSeekAfterPause()314     public void testSeekAfterPause() {
315         final AnimatorSet set = new AnimatorSet();
316         ValueAnimator a1 = ValueAnimator.ofFloat(0f, 50f);
317         a1.setDuration(50);
318         ValueAnimator a2 = ValueAnimator.ofFloat(50, 100f);
319         a2.setDuration(50);
320         set.playSequentially(a1, a2);
321         set.setInterpolator(new LinearInterpolator());
322 
323         set.start();
324         set.pause();
325         set.setCurrentPlayTime(60);
326         assertEquals((long) set.getCurrentPlayTime(), 60);
327         assertEquals((float) a1.getAnimatedValue(), 50f, EPSILON);
328         assertEquals((float) a2.getAnimatedValue(), 60f, EPSILON);
329 
330         set.setCurrentPlayTime(40);
331         assertEquals((long) set.getCurrentPlayTime(), 40);
332         assertEquals((float) a1.getAnimatedValue(), 40f, EPSILON);
333         assertEquals((float) a2.getAnimatedValue(), 50f, EPSILON);
334 
335         set.cancel();
336     }
337 
338     @UiThreadTest
339     @Test
testSeekListener()340     public void testSeekListener() {
341         final AnimatorSet animatorSet = new AnimatorSet();
342         ValueAnimator anim = ValueAnimator.ofFloat(0f, 1000f);
343         anim.setDuration(1000);
344         animatorSet.playTogether(anim);
345         final AtomicLong notifiedPlayTime = new AtomicLong(0L);
346         animatorSet.addUpdateListener((animation) -> {
347             final AnimatorSet set = (AnimatorSet) animation;
348             notifiedPlayTime.set(set.getCurrentPlayTime());
349         });
350         animatorSet.setCurrentPlayTime(0L);
351         assertEquals(0L, notifiedPlayTime.get());
352         animatorSet.setCurrentPlayTime(100L);
353         assertEquals(100L, notifiedPlayTime.get());
354     }
355 
356     @UiThreadTest
357     @Test
testDuration()358     public void testDuration() {
359         mAnim1.setRepeatCount(ValueAnimator.INFINITE);
360         Animator[] animatorArray = {mAnim1, mAnim2};
361 
362         mAnimatorSet = new AnimatorSet();
363         mAnimatorSet.playTogether(animatorArray);
364         mAnimatorSet.setDuration(1000);
365 
366         assertEquals(mAnimatorSet.getDuration(), 1000);
367     }
368 
369     @UiThreadTest
370     @Test
testStartDelay()371     public void testStartDelay() {
372         mAnim1.setRepeatCount(ValueAnimator.INFINITE);
373         Animator[] animatorArray = {mAnim1, mAnim2};
374 
375         mAnimatorSet = new AnimatorSet();
376         mAnimatorSet.playTogether(animatorArray);
377         mAnimatorSet.setStartDelay(10);
378 
379         assertEquals(mAnimatorSet.getStartDelay(), 10);
380     }
381 
382     /**
383      * This test sets up an AnimatorSet with start delay. One of the child animators also has
384      * start delay. We then verify that start delay was handled correctly on both AnimatorSet
385      * and individual animator level.
386      */
387     @UiThreadTest
388     @Test
testReverseWithStartDelay()389     public void testReverseWithStartDelay() {
390         ValueAnimator a1 = ValueAnimator.ofFloat(0f, 1f);
391         a1.setDuration(200);
392 
393         ValueAnimator a2 = ValueAnimator.ofFloat(1f, 2f);
394         a2.setDuration(200);
395         // Set start delay on a2 so that the delay is passed 100ms after a1 is finished.
396         a2.setStartDelay(300);
397 
398         AnimatorSet set = new AnimatorSet();
399         set.playTogether(a1, a2);
400         set.setStartDelay(1000);
401 
402         set.reverse();
403         sAnimatorTestRule.advanceTimeBy(0);
404         assertTrue(a2.isStarted());
405         assertTrue(a2.isRunning());
406         assertFalse(a1.isStarted());
407 
408         // a2 should finish 200ms after reverse started
409         sAnimatorTestRule.advanceTimeBy(200);
410         assertFalse(a2.isStarted());
411         // By the time a2 finishes reversing, a1 should not have started.
412         assertFalse(a1.isStarted());
413 
414         sAnimatorTestRule.advanceTimeBy(100);
415         assertTrue(a1.isStarted());
416 
417         // a1 finishes within 200ms after starting
418         sAnimatorTestRule.advanceTimeBy(200);
419         assertFalse(a1.isStarted());
420         assertFalse(set.isStarted());
421 
422         set.cancel();
423     }
424 
425     /**
426      * Test that duration scale is handled correctly in the AnimatorSet.
427      */
428     @UiThreadTest
429     @Test
testZeroDurationScale()430     public void testZeroDurationScale() {
431         ValueAnimator.setDurationScale(0);
432 
433         AnimatorSet set = new AnimatorSet();
434         set.playSequentially(mAnim1, mAnim2);
435         set.setStartDelay(1000);
436 
437         set.start();
438         assertFalse(set.isStarted());
439     }
440 
441     /**
442      * Test that non-zero duration scale is handled correctly in the AnimatorSet.
443      */
444     @UiThreadTest
445     @Test
testDurationScale()446     public void testDurationScale() {
447         // Change the duration scale to 3
448         ValueAnimator.setDurationScale(3f);
449 
450         ValueAnimator a1 = ValueAnimator.ofFloat(0f, 1f);
451         a1.setDuration(100);
452 
453         ValueAnimator a2 = ValueAnimator.ofFloat(1f, 2f);
454         a2.setDuration(100);
455         // Set start delay on a2 so that the delay is passed 100ms after a1 is finished.
456         a2.setStartDelay(200);
457 
458         AnimatorSet set = new AnimatorSet();
459         set.playSequentially(a1, a2);
460         set.setStartDelay(200);
461 
462         // Sleep for part of the start delay and check that no child animator has started, to verify
463         // that the duration scale has been properly scaled.
464         set.start();
465         sAnimatorTestRule.advanceTimeBy(0);
466         assertFalse(set.isRunning());
467         // start delay of the set should be scaled to 600ms
468         sAnimatorTestRule.advanceTimeBy(550);
469         assertFalse(set.isRunning());
470 
471         sAnimatorTestRule.advanceTimeBy(50);
472         assertTrue(set.isRunning());
473         assertTrue(a1.isStarted());
474         assertFalse(a2.isStarted());
475 
476         // Verify that a1 finish in 300ms (3x its defined duration)
477         sAnimatorTestRule.advanceTimeBy(300);
478         assertFalse(a1.isStarted());
479         assertTrue(a2.isStarted());
480         assertFalse(a2.isRunning());
481 
482         // a2 should finish the delay stage now
483         sAnimatorTestRule.advanceTimeBy(600);
484         assertTrue(a2.isStarted());
485         assertTrue(a2.isRunning());
486 
487         sAnimatorTestRule.advanceTimeBy(300);
488         assertFalse(a2.isStarted());
489         assertFalse(a2.isRunning());
490         assertFalse(set.isStarted());
491     }
492 
493     @UiThreadTest
494     @Test
testClone()495     public void testClone() {
496         final AnimatorSet set1 = new AnimatorSet();
497         final AnimatorListenerAdapter setListener = new AnimatorListenerAdapter() {};
498         set1.addListener(setListener);
499 
500         ObjectAnimator animator1 = new ObjectAnimator();
501         animator1.setDuration(100);
502         animator1.setPropertyName("x");
503         animator1.setIntValues(5);
504         animator1.setInterpolator(new LinearInterpolator());
505         AnimatorListenerAdapter listener1 = new AnimatorListenerAdapter(){};
506         AnimatorListenerAdapter listener2 = new AnimatorListenerAdapter(){};
507         animator1.addListener(listener1);
508 
509         ObjectAnimator animator2 = new ObjectAnimator();
510         animator2.setDuration(100);
511         animator2.setInterpolator(new LinearInterpolator());
512         animator2.addListener(listener2);
513         animator2.setPropertyName("y");
514         animator2.setIntValues(10);
515 
516         set1.playTogether(animator1, animator2);
517 
518         class AnimateObject {
519             public int x = 1;
520             public int y = 2;
521             public void setX(int val) {
522                 x = val;
523             }
524 
525             public void setY(int val) {
526                 y = val;
527             }
528         }
529         set1.setTarget(new AnimateObject());
530 
531         set1.start();
532         assertTrue(set1.isStarted());
533 
534         animator1.getListeners();
535         AnimatorSet set2 = set1.clone();
536         assertFalse(set2.isStarted());
537 
538         assertEquals(2, set2.getChildAnimations().size());
539 
540         Animator clone1 = set2.getChildAnimations().get(0);
541         Animator clone2 = set2.getChildAnimations().get(1);
542 
543         assertTrue(clone1.getListeners().contains(listener1));
544         assertTrue(clone2.getListeners().contains(listener2));
545 
546         assertTrue(set2.getListeners().contains(setListener));
547 
548         for (Animator.AnimatorListener listener : set1.getListeners()) {
549             assertTrue(set2.getListeners().contains(listener));
550         }
551 
552         assertEquals(animator1.getDuration(), clone1.getDuration());
553         assertEquals(animator2.getDuration(), clone2.getDuration());
554         assertSame(animator1.getInterpolator(), clone1.getInterpolator());
555         assertSame(animator2.getInterpolator(), clone2.getInterpolator());
556         set1.cancel();
557     }
558 
559     /**
560      * Testing seeking in an AnimatorSet containing sequential animators.
561      */
562     @UiThreadTest
563     @Test
testSeeking()564     public void testSeeking() {
565         final AnimatorSet set = new AnimatorSet();
566         final ValueAnimator a1 = ValueAnimator.ofFloat(0f, 150f);
567         a1.setDuration(150);
568         final ValueAnimator a2 = ValueAnimator.ofFloat(150f, 250f);
569         a2.setDuration(100);
570         final ValueAnimator a3 = ValueAnimator.ofFloat(250f, 300f);
571         a3.setDuration(50);
572 
573         a1.setInterpolator(null);
574         a2.setInterpolator(null);
575         a3.setInterpolator(null);
576 
577         set.playSequentially(a1, a2, a3);
578 
579         set.setCurrentPlayTime(100);
580         assertEquals(100f, (Float) a1.getAnimatedValue(), EPSILON);
581         assertEquals(150f, (Float) a2.getAnimatedValue(), EPSILON);
582         assertEquals(250f, (Float) a3.getAnimatedValue(), EPSILON);
583 
584         set.setCurrentPlayTime(280);
585         assertEquals(150f, (Float) a1.getAnimatedValue(), EPSILON);
586         assertEquals(250f, (Float) a2.getAnimatedValue(), EPSILON);
587         assertEquals(280f, (Float) a3.getAnimatedValue(), EPSILON);
588 
589         set.start();
590         sAnimatorTestRule.advanceTimeBy(0);
591         assertEquals(280, set.getCurrentPlayTime());
592         assertTrue(set.isRunning());
593         sAnimatorTestRule.advanceTimeBy(20);
594         assertFalse(set.isStarted());
595 
596         // Seek after a run to the middle-ish, and verify the first animator is at the end
597         // value and the 3rd at beginning value, and the 2nd animator is at the seeked value.
598         set.setCurrentPlayTime(200);
599         assertEquals(150f, (Float) a1.getAnimatedValue(), EPSILON);
600         assertEquals(200f, (Float) a2.getAnimatedValue(), EPSILON);
601         assertEquals(250f, (Float) a3.getAnimatedValue(), EPSILON);
602     }
603 
604     /**
605      * Testing seeking in an AnimatorSet containing infinite animators.
606      */
607     @Test
testSeekingInfinite()608     public void testSeekingInfinite() {
609         final AnimatorSet set = new AnimatorSet();
610         final ValueAnimator a1 = ValueAnimator.ofFloat(0f, 100f);
611         a1.setDuration(100);
612         final ValueAnimator a2 = ValueAnimator.ofFloat(100f, 200f);
613         a2.setDuration(100);
614         a2.setRepeatCount(ValueAnimator.INFINITE);
615         a2.setRepeatMode(ValueAnimator.RESTART);
616 
617         final ValueAnimator a3 = ValueAnimator.ofFloat(100f, 200f);
618         a3.setDuration(100);
619         a3.setRepeatCount(ValueAnimator.INFINITE);
620         a3.setRepeatMode(ValueAnimator.REVERSE);
621 
622         a1.setInterpolator(null);
623         a2.setInterpolator(null);
624         a3.setInterpolator(null);
625         set.play(a1).before(a2);
626         set.play(a1).before(a3);
627 
628         set.setCurrentPlayTime(50);
629         assertEquals(50L, set.getCurrentPlayTime());
630         assertEquals(50f, (Float) a1.getAnimatedValue(), EPSILON);
631         assertEquals(100f, (Float) a2.getAnimatedValue(), EPSILON);
632         assertEquals(100f, (Float) a3.getAnimatedValue(), EPSILON);
633 
634         set.setCurrentPlayTime(100);
635         assertEquals(100L, set.getCurrentPlayTime());
636         assertEquals(100f, (Float) a1.getAnimatedValue(), EPSILON);
637         assertEquals(100f, (Float) a2.getAnimatedValue(), EPSILON);
638         assertEquals(100f, (Float) a3.getAnimatedValue(), EPSILON);
639 
640         // Seek to the 1st iteration of the infinite repeat animators, and they should have the
641         // same value.
642         set.setCurrentPlayTime(180);
643         assertEquals(180L, set.getCurrentPlayTime());
644         assertEquals(100f, (Float) a1.getAnimatedValue(), EPSILON);
645         assertEquals(180f, (Float) a2.getAnimatedValue(), EPSILON);
646         assertEquals(180f, (Float) a3.getAnimatedValue(), EPSILON);
647 
648         // Seek to the 2nd iteration of the infinite repeat animators, and they should have
649         // different values as they have different repeat mode.
650         set.setCurrentPlayTime(280);
651         assertEquals(280L, set.getCurrentPlayTime());
652         assertEquals(100f, (Float) a1.getAnimatedValue(), EPSILON);
653         assertEquals(180f, (Float) a2.getAnimatedValue(), EPSILON);
654         assertEquals(120f, (Float) a3.getAnimatedValue(), EPSILON);
655 
656     }
657 
658     @UiThreadTest
659     @Test
testSeekNested()660     public void testSeekNested() {
661         final AnimatorSet parent = new AnimatorSet();
662         final ValueAnimator a1 = ValueAnimator.ofFloat(0f, 100f);
663         a1.setDuration(100);
664         final AnimatorSet child = new AnimatorSet();
665         child.playTogether(a1);
666         final ValueAnimator a2 = ValueAnimator.ofFloat(100f, 200f);
667         a2.setDuration(100);
668         parent.playTogether(child, a2);
669 
670         parent.setCurrentPlayTime(50);
671         assertEquals(50f, (float) a1.getAnimatedValue(), EPSILON);
672         assertEquals(150f, (float) a2.getAnimatedValue(), EPSILON);
673     }
674 
675     @UiThreadTest
676     @Test
testNotifiesAfterEnd()677     public void testNotifiesAfterEnd() {
678         final ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
679         class TestListener extends AnimatorListenerAdapter {
680             public boolean startIsCalled = false;
681             public boolean endIsCalled = false;
682             @Override
683             public void onAnimationStart(@NonNull Animator animation) {
684                 assertTrue(animation.isStarted());
685                 assertTrue(animation.isRunning());
686                 startIsCalled = true;
687             }
688 
689             @Override
690             public void onAnimationEnd(@NonNull Animator animation) {
691                 assertFalse(animation.isRunning());
692                 assertFalse(animation.isStarted());
693                 super.onAnimationEnd(animation);
694                 endIsCalled = true;
695             }
696         }
697         TestListener listener = new TestListener();
698         animator.addListener(listener);
699 
700         TestListener setListener = new TestListener();
701         final AnimatorSet animatorSet = new AnimatorSet();
702         animatorSet.playTogether(animator);
703         animatorSet.addListener(setListener);
704 
705         animatorSet.start();
706         animator.end();
707         assertFalse(animator.isStarted());
708 
709         assertTrue(listener.startIsCalled);
710         assertTrue(listener.endIsCalled);
711         assertTrue(setListener.startIsCalled);
712     }
713 
714     /**
715      *
716      * This test verifies that custom ValueAnimators will be start()'ed in a set.
717      */
718     @UiThreadTest
719     @Test
testChildAnimatorStartCalled()720     public void testChildAnimatorStartCalled() {
721         class StartListener extends AnimatorListenerAdapter {
722             public boolean mStartCalled = false;
723             @Override
724             public void onAnimationStart(@NonNull Animator anim) {
725                 mStartCalled = true;
726             }
727         }
728 
729         StartListener l1 = new StartListener();
730         StartListener l2 = new StartListener();
731         mAnim1.addListener(l1);
732         mAnim2.addListener(l2);
733 
734         AnimatorSet set = new AnimatorSet();
735         set.playTogether(mAnim1, mAnim2);
736         set.start();
737         assertTrue(l1.mStartCalled);
738         assertTrue(l2.mStartCalled);
739     }
740 
741     /**
742      * This test sets up an AnimatorSet that contains two sequential animations. The first animation
743      * is infinite, the second animation therefore has an infinite start time. This test verifies
744      * that the infinite start time is handled correctly.
745      */
746     @UiThreadTest
747     @Test
testInfiniteStartTime()748     public void testInfiniteStartTime() {
749         ValueAnimator a1 = ValueAnimator.ofFloat(0f, 1f);
750         a1.setRepeatCount(ValueAnimator.INFINITE);
751         ValueAnimator a2 = ValueAnimator.ofFloat(0f, 1f);
752 
753         AnimatorSet set = new AnimatorSet();
754         set.playSequentially(a1, a2);
755 
756         set.start();
757 
758         assertEquals(Animator.DURATION_INFINITE, set.getTotalDuration());
759 
760         set.end();
761     }
762 
763     /**
764      * This test sets up 10 animators playing together. We expect the start time for all animators
765      * to be the same.
766      */
767     @UiThreadTest
768     @Test
testMultipleAnimatorsPlayTogether()769     public void testMultipleAnimatorsPlayTogether() {
770         Animator[] animators = new Animator[10];
771         for (int i = 0; i < 10; i++) {
772             animators[i] = ValueAnimator.ofFloat(0f, 1f);
773             animators[i].setDuration(100 + i * 100);
774         }
775         AnimatorSet set = new AnimatorSet();
776         set.playTogether(animators);
777         set.setStartDelay(80);
778 
779         set.start();
780         sAnimatorTestRule.advanceTimeBy(0);
781         assertTrue(set.isStarted());
782         assertFalse(set.isRunning());
783         sAnimatorTestRule.advanceTimeBy(80);
784         for (int i = 0; i < 10; i++) {
785             assertTrue(animators[i].isRunning());
786             sAnimatorTestRule.advanceTimeBy(100);
787             assertFalse(animators[i].isStarted());
788         }
789 
790         // The set should finish by now.
791         assertFalse(set.isStarted());
792     }
793 
794     @UiThreadTest
795     @Test
testGetChildAnimations()796     public void testGetChildAnimations() {
797         Animator[] animatorArray = {mAnim1, mAnim2};
798 
799         mAnimatorSet = new AnimatorSet();
800         mAnimatorSet.getChildAnimations();
801         assertEquals(0, mAnimatorSet.getChildAnimations().size());
802         mAnimatorSet.playSequentially(animatorArray);
803         assertEquals(2, mAnimatorSet.getChildAnimations().size());
804     }
805 
806     /**
807      *
808      */
809     @UiThreadTest
810     @Test
testSetInterpolator()811     public void testSetInterpolator() {
812         mAnim1.setRepeatCount(ValueAnimator.INFINITE);
813         Animator[] animatorArray = {mAnim1, mAnim2};
814 
815         Interpolator interpolator = new AccelerateDecelerateInterpolator();
816         mAnimatorSet = new AnimatorSet();
817         mAnimatorSet.playTogether(animatorArray);
818         mAnimatorSet.setInterpolator(interpolator);
819 
820         assertFalse(mAnimatorSet.isRunning());
821         mAnimatorSet.start();
822 
823         ArrayList<Animator> animatorList = mAnimatorSet.getChildAnimations();
824         assertEquals(interpolator, animatorList.get(0).getInterpolator());
825         assertEquals(interpolator, animatorList.get(1).getInterpolator());
826         mAnimatorSet.cancel();
827     }
828 
829     @UiThreadTest
830     @Test
testMultipleAnimatorsSingleProperty()831     public void testMultipleAnimatorsSingleProperty() {
832         final SampleTarget target = new SampleTarget();
833         final ObjectAnimator a1 = ObjectAnimator.ofFloat(target, SampleTarget.VALUE, 0f, 1000f);
834         a1.setDuration(1000);
835         a1.setInterpolator(new LinearInterpolator());
836         final ObjectAnimator a2 = ObjectAnimator.ofFloat(target, SampleTarget.VALUE, 1000f, 2000f);
837         a2.setDuration(1000);
838         a2.setStartDelay(1000);
839         a2.setInterpolator(new LinearInterpolator());
840         final AnimatorSet set = new AnimatorSet();
841         set.playTogether(a1, a2);
842 
843         set.start();
844 
845         final float delta = 0.001f;
846         assertEquals(0f, target.mValue, delta);
847 
848         sAnimatorTestRule.advanceTimeBy(500);
849         assertEquals(500f, (float) a1.getAnimatedValue(), delta);
850         assertEquals(500f, target.mValue, delta);
851 
852         sAnimatorTestRule.advanceTimeBy(1000);
853         assertEquals(1500f, target.mValue, delta);
854 
855         sAnimatorTestRule.advanceTimeBy(5000);
856         assertEquals(2000f, target.mValue, delta);
857         assertFalse(set.isRunning());
858 
859         // Rewind
860         set.setCurrentPlayTime(1500);
861         assertEquals(1500f, target.mValue, delta);
862 
863         set.setCurrentPlayTime(500);
864         assertEquals(500f, target.mValue, delta);
865     }
866 
867     static class SampleTarget {
868 
869         static final Property<SampleTarget, Float> VALUE = new FloatProperty<SampleTarget>() {
870             @Override
871             public void setValue(@NonNull SampleTarget object, float value) {
872                 object.mValue = value;
873             }
874 
875             @Override
876             public Float get(SampleTarget sampleTarget) {
877                 return sampleTarget.mValue;
878             }
879         };
880 
881         float mValue;
882     }
883 
884     static class AnimEvent {
885         enum EventType {
886             START,
887             END
888         }
889         final EventType mType;
890         final Animator mAnim;
AnimEvent(EventType type, Animator anim)891         AnimEvent(EventType type, Animator anim) {
892             mType = type;
893             mAnim = anim;
894         }
895     }
896 }
897