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