ValueAnimatorTests.java revision a0942e212154655c16849a9c6218f54694b4203a
1/*
2* Copyright (C) 2015 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*/
16package android.animation;
17
18import android.os.Handler;
19import android.os.Looper;
20import android.os.Message;
21import android.os.SystemClock;
22import android.test.ActivityInstrumentationTestCase2;
23import android.test.suitebuilder.annotation.SmallTest;
24import android.view.Choreographer;
25import android.view.animation.LinearInterpolator;
26
27import java.util.ArrayList;
28
29import static android.test.MoreAsserts.assertNotEqual;
30
31public class ValueAnimatorTests extends ActivityInstrumentationTestCase2<BasicAnimatorActivity> {
32    private static final long WAIT_TIME_OUT = 5000;
33    private ValueAnimator a1;
34    private ValueAnimator a2;
35
36    // Tolerance of error in calculations related to duration, frame time, etc. due to frame delay.
37    private final static long TOLERANCE = 100; // ms
38    private final static long POLL_INTERVAL = 100; // ms
39
40    private final static float A1_START_VALUE = 0f;
41    private final static float A1_END_VALUE = 1f;
42    private final static int A2_START_VALUE = 100;
43    private final static int A2_END_VALUE = 200;
44
45    private final static long DEFAULT_FRAME_INTERVAL = 5; //ms
46    private final static long COMMIT_DELAY = 3; //ms
47
48    public ValueAnimatorTests() {
49        super(BasicAnimatorActivity.class);
50    }
51
52    @Override
53    public void setUp() throws Exception {
54        super.setUp();
55        a1 = ValueAnimator.ofFloat(A1_START_VALUE, A1_END_VALUE).setDuration(300);
56        a2 = ValueAnimator.ofInt(A2_START_VALUE, A2_END_VALUE).setDuration(500);
57    }
58
59    @Override
60    public void tearDown() throws Exception {
61        a1 = null;
62        a2 = null;
63        super.tearDown();
64    }
65
66    @SmallTest
67    public void testStartDelay() throws Throwable {
68        final ValueAnimator a = ValueAnimator.ofFloat(5f, 20f);
69        assertEquals(a.getStartDelay(), 0);
70        final long delay = 200;
71        a.setStartDelay(delay);
72        assertEquals(a.getStartDelay(), delay);
73
74        final MyUpdateListener listener = new MyUpdateListener();
75        a.addUpdateListener(listener);
76        final long[] startTime = new long[1];
77
78        runTestOnUiThread(new Runnable() {
79            @Override
80            public void run() {
81                // Test the time between isRunning() and isStarted()
82                assertFalse(a.isStarted());
83                assertFalse(a.isRunning());
84                a.start();
85                startTime[0] = SystemClock.uptimeMillis();
86                assertTrue(a.isStarted());
87                assertFalse(a.isRunning());
88            }
89        });
90
91        Thread.sleep(a.getTotalDuration());
92        runTestOnUiThread(new Runnable() {
93            @Override
94            public void run() {
95                assertTrue(listener.wasRunning);
96                assertTrue(listener.firstRunningFrameTime - startTime[0] >= delay);
97            }
98        });
99
100        Thread.sleep(a.getTotalDuration());
101        runTestOnUiThread(new Runnable() {
102            @Override
103            public void run() {
104                assertFalse(a.isStarted());
105            }
106        });
107    }
108
109    @SmallTest
110    public void testListenerCallbacks() throws Throwable {
111        final MyListener l1 = new MyListener();
112        final MyListener l2 = new MyListener();
113        a1.addListener(l1);
114        a2.addListener(l2);
115        a2.setStartDelay(400);
116
117        assertFalse(l1.startCalled);
118        assertFalse(l1.cancelCalled);
119        assertFalse(l1.endCalled);
120        assertFalse(l2.startCalled);
121        assertFalse(l2.cancelCalled);
122        assertFalse(l2.endCalled);
123
124        runTestOnUiThread(new Runnable() {
125            @Override
126            public void run() {
127                a1.start();
128                a2.start();
129            }
130        });
131
132        long wait = 0;
133        Thread.sleep(POLL_INTERVAL);
134        wait += POLL_INTERVAL;
135
136        runTestOnUiThread(new Runnable() {
137            @Override
138            public void run() {
139                assertFalse(l1.cancelCalled);
140                a1.cancel();
141                assertTrue(l1.cancelCalled);
142                assertTrue(l1.endCalled);
143            }
144        });
145
146        while (wait < a2.getStartDelay()) {
147            runTestOnUiThread(new Runnable() {
148                @Override
149                public void run() {
150                    // Make sure a2's start listener isn't called during start delay.
151                    assertTrue(l1.startCalled);
152                    assertFalse(l2.startCalled);
153                }
154            });
155            Thread.sleep(POLL_INTERVAL);
156            wait += POLL_INTERVAL;
157        }
158
159        long delay = Math.max(a1.getTotalDuration(), a2.getTotalDuration()) + TOLERANCE;
160        Thread.sleep(delay);
161
162        runTestOnUiThread(new Runnable() {
163            @Override
164            public void run() {
165                // a1 is canceled.
166                assertTrue(l1.startCalled);
167                assertTrue(l1.cancelCalled);
168                assertTrue(l1.endCalled);
169
170                // a2 is supposed to finish normally
171                assertTrue(l2.startCalled);
172                assertFalse(l2.cancelCalled);
173                assertTrue(l2.endCalled);
174            }
175        });
176    }
177
178    @SmallTest
179    public void testIsStarted() throws Throwable {
180        assertFalse(a1.isStarted());
181        assertFalse(a2.isStarted());
182        assertFalse(a1.isRunning());
183        assertFalse(a2.isRunning());
184        final long startDelay = 150;
185        a1.setStartDelay(startDelay);
186        final long[] startTime = new long[1];
187
188        runTestOnUiThread(new Runnable() {
189            @Override
190            public void run() {
191                a1.start();
192                a2.start();
193                startTime[0] = SystemClock.uptimeMillis();
194                assertTrue(a1.isStarted());
195                assertTrue(a2.isStarted());
196            }
197        });
198        long delayMs = 0;
199        while (delayMs < startDelay) {
200            Thread.sleep(POLL_INTERVAL);
201            delayMs += POLL_INTERVAL;
202            runTestOnUiThread(new Runnable() {
203                @Override
204                public void run() {
205                    if (SystemClock.uptimeMillis() - startTime[0] < startDelay) {
206                        assertFalse(a1.isRunning());
207                    }
208                }
209            });
210        }
211
212        Thread.sleep(startDelay);
213        runTestOnUiThread(new Runnable() {
214            @Override
215            public void run() {
216                assertTrue(a1.isRunning());
217                assertTrue(a2.isRunning());
218            }
219        });
220
221        long delay = Math.max(a1.getTotalDuration(), a2.getTotalDuration()) * 2;
222        Thread.sleep(delay);
223        runTestOnUiThread(new Runnable() {
224            @Override
225            public void run() {
226                assertFalse(a1.isStarted());
227                assertFalse(a1.isRunning());
228                assertFalse(a2.isStarted());
229                assertFalse(a2.isRunning());
230            }
231        });
232    }
233
234    @SmallTest
235    public void testPause() throws Throwable {
236        runTestOnUiThread(new Runnable() {
237            @Override
238            public void run() {
239                assertFalse(a1.isPaused());
240                assertFalse(a2.isPaused());
241
242                a1.start();
243                a2.start();
244
245                assertFalse(a1.isPaused());
246                assertFalse(a2.isPaused());
247                assertTrue(a1.isStarted());
248                assertTrue(a2.isStarted());
249            }
250        });
251
252        Thread.sleep(POLL_INTERVAL);
253        runTestOnUiThread(new Runnable() {
254            @Override
255            public void run() {
256                assertTrue(a1.isRunning());
257                assertTrue(a2.isRunning());
258                a1.pause();
259                assertTrue(a1.isPaused());
260                assertFalse(a2.isPaused());
261                assertTrue(a1.isRunning());
262            }
263        });
264
265        Thread.sleep(a2.getTotalDuration());
266        runTestOnUiThread(new Runnable() {
267            @Override
268            public void run() {
269                // By this time, a2 should have finished, and a1 is still paused
270                assertFalse(a2.isStarted());
271                assertFalse(a2.isRunning());
272                assertTrue(a1.isStarted());
273                assertTrue(a1.isRunning());
274                assertTrue(a1.isPaused());
275
276                a1.resume();
277            }
278        });
279
280        Thread.sleep(POLL_INTERVAL);
281        runTestOnUiThread(new Runnable() {
282            @Override
283            public void run() {
284                assertTrue(a1.isRunning());
285                assertTrue(a1.isStarted());
286                assertFalse(a1.isPaused());
287            }
288        });
289
290        Thread.sleep(a1.getTotalDuration());
291        runTestOnUiThread(new Runnable() {
292            @Override
293            public void run() {
294                // a1 should finish by now.
295                assertFalse(a1.isRunning());
296                assertFalse(a1.isStarted());
297                assertFalse(a1.isPaused());
298            }
299        });
300
301    }
302
303    @SmallTest
304    public void testPauseListener() throws Throwable {
305        MyPauseListener l1 = new MyPauseListener();
306        MyPauseListener l2 = new MyPauseListener();
307        a1.addPauseListener(l1);
308        a2.addPauseListener(l2);
309
310        assertFalse(l1.pauseCalled);
311        assertFalse(l1.resumeCalled);
312        assertFalse(l2.pauseCalled);
313        assertFalse(l2.resumeCalled);
314
315        runTestOnUiThread(new Runnable() {
316            @Override
317            public void run() {
318                a1.start();
319                a2.start();
320            }
321        });
322
323        Thread.sleep(a1.getTotalDuration() / 2);
324        a1.pause();
325
326        Thread.sleep(a2.getTotalDuration());
327
328        // Only a1's pause listener should be called.
329        assertTrue(l1.pauseCalled);
330        assertFalse(l1.resumeCalled);
331        a1.resume();
332
333        Thread.sleep(a1.getTotalDuration());
334
335        assertTrue(l1.pauseCalled);
336        assertTrue(l1.resumeCalled);
337        assertFalse(l2.pauseCalled);
338        assertFalse(l2.resumeCalled);
339    }
340
341    @SmallTest
342    public void testResume() throws Throwable {
343        final MyUpdateListener l1 = new MyUpdateListener();
344        final long totalDuration = a1.getTotalDuration();
345        a1.addUpdateListener(l1);
346        // Set a longer duration on a1 for this test
347        a1.setDuration(1000);
348        assertTrue(l1.firstRunningFrameTime < 0);
349        assertTrue(l1.lastUpdateTime < 0);
350
351        final long[] lastUpdate = new long[1];
352
353        runTestOnUiThread(new Runnable() {
354            @Override
355            public void run() {
356                a1.start();
357            }
358        });
359
360        Thread.sleep(totalDuration / 2);
361
362        runTestOnUiThread(new Runnable() {
363            @Override
364            public void run() {
365                assertTrue(l1.firstRunningFrameTime > 0);
366                assertTrue(l1.lastUpdateTime > l1.firstRunningFrameTime);
367                lastUpdate[0] = l1.lastUpdateTime;
368                a1.pause();
369            }
370        });
371
372        Thread.sleep(totalDuration);
373
374        runTestOnUiThread(new Runnable() {
375            @Override
376            public void run() {
377                // There should be no update after pause()
378                assertEquals(lastUpdate[0], l1.lastUpdateTime);
379                a1.resume();
380            }
381        });
382
383        do {
384            Thread.sleep(POLL_INTERVAL);
385            runTestOnUiThread(new Runnable() {
386                @Override
387                public void run() {
388                    assertTrue(l1.lastUpdateTime > lastUpdate[0]);
389                    lastUpdate[0] = l1.lastUpdateTime;
390                }
391            });
392        } while (!a1.isStarted());
393
394        // Time between pause and resume: totalDuration
395        long entireSpan = totalDuration * 2;
396        long frameDelta = l1.lastUpdateTime - l1.firstRunningFrameTime;
397        assertTrue(Math.abs(entireSpan - frameDelta) < TOLERANCE);
398    }
399
400    @SmallTest
401    public void testEnd() throws Throwable {
402        final MyListener l1 = new MyListener();
403        final MyListener l2 = new MyListener();
404        a1.addListener(l1);
405        a2.addListener(l2);
406        a1.addListener(new MyListener() {
407            @Override
408            public void onAnimationEnd(Animator anim) {
409                anim.cancel();
410            }
411        });
412        a2.addListener(new MyListener() {
413            @Override
414            public void onAnimationCancel(Animator anim) {
415                anim.end();
416            }
417        });
418
419        runTestOnUiThread(new Runnable() {
420            @Override
421            public void run() {
422                assertFalse(l1.cancelCalled);
423                assertFalse(l1.endCalled);
424                assertFalse(l2.cancelCalled);
425                assertFalse(l2.endCalled);
426                a1.start();
427                a2.start();
428            }
429        });
430        Thread.sleep(POLL_INTERVAL);
431        runTestOnUiThread(new Runnable() {
432            @Override
433            public void run() {
434                a1.end();
435                a2.cancel();
436            }
437        });
438        Thread.sleep(POLL_INTERVAL);
439        runTestOnUiThread(new Runnable() {
440            @Override
441            public void run() {
442                // Calling cancel from onAnimationEnd will be ignored.
443                assertFalse(l1.cancelCalled);
444                assertTrue(l1.endCalled);
445                assertTrue(l2.cancelCalled);
446                assertTrue(l2.endCalled);
447
448                float value1 = (Float) a1.getAnimatedValue();
449                int value2 = (Integer) a2.getAnimatedValue();
450                assertEquals(A1_END_VALUE, value1);
451                assertEquals(A2_END_VALUE, value2);
452            }
453        });
454
455    }
456
457    @SmallTest
458    public void testEndValue() throws Throwable {
459        final MyListener l1 = new MyListener();
460        a1.addListener(l1);
461
462        final MyListener l2 = new MyListener();
463        a2.addListener(l2);
464
465        runTestOnUiThread(new Runnable() {
466            @Override
467            public void run() {
468                a1.start();
469                a2.start();
470            }
471        });
472
473        Thread.sleep(POLL_INTERVAL);
474        runTestOnUiThread(new Runnable() {
475            @Override
476            public void run() {
477                // Animation has started but not finished, check animated values against end values
478                assertFalse(l1.endCalled);
479                assertFalse(l2.endCalled);
480                assertNotEqual(A1_END_VALUE, a1.getAnimatedValue());
481                assertNotEqual(A1_END_VALUE, a2.getAnimatedValue());
482
483                // Force a2 to end.
484                a2.end();
485            }
486        });
487
488        Thread.sleep(a1.getTotalDuration());
489
490        runTestOnUiThread(new Runnable() {
491            @Override
492            public void run() {
493                assertFalse(l1.cancelCalled);
494                assertTrue(l1.endCalled);
495                assertFalse(l2.cancelCalled);
496                assertTrue(l2.endCalled);
497
498                // By now a1 should have finished normally and a2 has skipped to the end, check
499                // their end values.
500                assertEquals(A1_END_VALUE, ((Float) (a1.getAnimatedValue())).floatValue());
501                assertEquals(A2_END_VALUE, ((Integer) (a2.getAnimatedValue())).intValue());
502            }
503        });
504    }
505
506    @SmallTest
507    public void testUpdateListener() throws InterruptedException {
508
509        final MyFrameCallbackProvider provider = new MyFrameCallbackProvider();
510        long sleep = 0;
511        while (provider.mHandler == null) {
512            Thread.sleep(POLL_INTERVAL);
513            sleep += POLL_INTERVAL;
514            if (sleep > WAIT_TIME_OUT) {
515                break;
516            }
517        }
518        // Either the looper has started, or timed out
519        assertNotNull(provider.mHandler);
520
521        final MyListener listener = new MyListener();
522        final MyUpdateListener l1 = new MyUpdateListener() {
523            @Override
524            public void onAnimationUpdate(ValueAnimator animation) {
525                long currentTime = SystemClock.uptimeMillis();
526                long frameDelay = provider.getFrameDelay();
527                if (lastUpdateTime > 0) {
528                    // Error tolerance here is one frame.
529                    assertTrue((currentTime - lastUpdateTime) < frameDelay * 2);
530                } else {
531                    // First frame:
532                    assertTrue(listener.startCalled);
533                    assertTrue(listener.startTime > 0);
534                    assertTrue(currentTime - listener.startTime < frameDelay * 2);
535                }
536                super.onAnimationUpdate(animation);
537            }
538        };
539        a1.addUpdateListener(l1);
540        a1.addListener(listener);
541        a1.setStartDelay(100);
542
543        provider.mHandler.post(new Runnable() {
544            @Override
545            public void run() {
546                AnimationHandler.getInstance().setProvider(provider);
547                a1.start();
548            }
549        });
550        Thread.sleep(POLL_INTERVAL);
551        assertTrue(a1.isStarted());
552        Thread.sleep(a1.getTotalDuration() + TOLERANCE);
553        // Finished by now.
554        assertFalse(a1.isStarted());
555        assertTrue(listener.endTime > 0);
556
557        // Check the time difference between last frame and end time.
558        assertTrue(listener.endTime >= l1.lastUpdateTime);
559        assertTrue(listener.endTime - l1.lastUpdateTime < 2 * provider.getFrameDelay());
560    }
561
562
563    @SmallTest
564    public void testConcurrentModification() throws Throwable {
565        // Attempt to modify list of animations as the list is being iterated
566        final ValueAnimator a0 = ValueAnimator.ofInt(100, 200).setDuration(500);
567        final ValueAnimator a3 = ValueAnimator.ofFloat(0, 1).setDuration(500);
568        final ValueAnimator a4 = ValueAnimator.ofInt(200, 300).setDuration(500);
569        final MyListener listener = new MyListener() {
570            @Override
571            public void onAnimationEnd(Animator anim) {
572                super.onAnimationEnd(anim);
573                // AnimationHandler should be iterating the list at the moment, end/cancel all
574                // the other animations. No ConcurrentModificationException should happen.
575                a0.cancel();
576                a1.end();
577                a3.end();
578                a4.cancel();
579            }
580        };
581        a2.addListener(listener);
582
583        runTestOnUiThread(new Runnable() {
584            @Override
585            public void run() {
586                a0.start();
587                a1.start();
588                a2.start();
589                a3.start();
590                a4.start();
591            }
592        });
593        runTestOnUiThread(new Runnable() {
594            @Override
595            public void run() {
596                assertTrue(a0.isStarted());
597                assertTrue(a1.isStarted());
598                assertTrue(a2.isStarted());
599                assertTrue(a3.isStarted());
600                assertTrue(a4.isStarted());
601            }
602        });
603        Thread.sleep(POLL_INTERVAL);
604        runTestOnUiThread(new Runnable() {
605            @Override
606            public void run() {
607                // End the animator that should be in the middle of the list.
608                a2.end();
609            }
610        });
611        Thread.sleep(POLL_INTERVAL);
612        assertTrue(listener.endCalled);
613        assertFalse(a0.isStarted());
614        assertFalse(a1.isStarted());
615        assertFalse(a2.isStarted());
616        assertFalse(a3.isStarted());
617        assertFalse(a4.isStarted());
618    }
619
620    @SmallTest
621    public void testSeek() throws Throwable {
622        final MyListener l1 = new MyListener();
623        final MyListener l2 = new MyListener();
624        final MyUpdateListener updateListener1 = new MyUpdateListener();
625        final MyUpdateListener updateListener2 = new MyUpdateListener();
626        final float a1StartFraction = 0.2f;
627        final float a2StartFraction = 0.3f;
628
629        // Extend duration so we have plenty of latitude to manipulate the animations when they
630        // are running.
631        a1.setDuration(1000);
632        a2.setDuration(1000);
633        a1.addListener(l1);
634        a2.addListener(l2);
635        a1.addUpdateListener(updateListener1);
636        a2.addUpdateListener(updateListener2);
637        TimeInterpolator interpolator = new LinearInterpolator();
638        a1.setInterpolator(interpolator);
639        a2.setInterpolator(interpolator);
640
641        runTestOnUiThread(new Runnable() {
642            @Override
643            public void run() {
644                assertFalse(a1.isStarted());
645                assertFalse(a1.isRunning());
646                assertFalse(a2.isStarted());
647                assertFalse(a2.isRunning());
648
649                // Test isRunning() and isStarted() before and after seek
650                a1.setCurrentFraction(a1StartFraction);
651                a2.setCurrentFraction(a2StartFraction);
652
653                assertFalse(a1.isStarted());
654                assertFalse(a1.isRunning());
655                assertFalse(a2.isStarted());
656                assertFalse(a2.isRunning());
657            }
658        });
659        Thread.sleep(POLL_INTERVAL);
660
661        // Start animation and seek during the animation.
662        runTestOnUiThread(new Runnable() {
663            @Override
664            public void run() {
665                assertFalse(a1.isStarted());
666                assertFalse(a1.isRunning());
667                assertFalse(a2.isStarted());
668                assertFalse(a2.isRunning());
669                assertEquals(a1StartFraction, a1.getAnimatedFraction());
670                assertEquals(a2StartFraction, a2.getAnimatedFraction());
671
672                a1.start();
673                a2.start();
674            }
675        });
676
677        Thread.sleep(POLL_INTERVAL);
678        final float halfwayFraction = 0.5f;
679        runTestOnUiThread(new Runnable() {
680            @Override
681            public void run() {
682                assertTrue(l1.startCalled);
683                assertTrue(l2.startCalled);
684                assertFalse(l1.endCalled);
685                assertFalse(l2.endCalled);
686
687                // Check whether the animations start from the seeking fraction
688                assertTrue(updateListener1.startFraction >= a1StartFraction);
689                assertTrue(updateListener2.startFraction >= a2StartFraction);
690
691                assertTrue(a1.isStarted());
692                assertTrue(a1.isRunning());
693                assertTrue(a2.isStarted());
694                assertTrue(a2.isRunning());
695
696                a1.setCurrentFraction(halfwayFraction);
697                a2.setCurrentFraction(halfwayFraction);
698            }
699        });
700
701        Thread.sleep(POLL_INTERVAL);
702
703        // Check that seeking during running doesn't change animation's internal state
704        runTestOnUiThread(new Runnable() {
705            @Override
706            public void run() {
707                assertTrue(l1.startCalled);
708                assertTrue(l2.startCalled);
709                assertFalse(l1.endCalled);
710                assertFalse(l2.endCalled);
711
712                assertTrue(a1.isStarted());
713                assertTrue(a1.isRunning());
714                assertTrue(a2.isStarted());
715                assertTrue(a2.isRunning());
716            }
717        });
718
719        // Wait until the animators finish successfully.
720        long wait = Math.max(a1.getTotalDuration(), a2.getTotalDuration());
721        Thread.sleep(wait);
722
723        runTestOnUiThread(new Runnable() {
724            @Override
725            public void run() {
726                // Verify that the animators have finished.
727                assertTrue(l1.endCalled);
728                assertTrue(l2.endCalled);
729
730                assertFalse(a1.isStarted());
731                assertFalse(a2.isStarted());
732                assertFalse(a1.isRunning());
733                assertFalse(a2.isRunning());
734            }
735        });
736
737        // Re-start animator a1 after it ends normally, and check that seek value from last run
738        // does not affect the new run.
739        updateListener1.reset();
740        runTestOnUiThread(new Runnable() {
741            @Override
742            public void run() {
743                a1.start();
744            }
745        });
746
747        Thread.sleep(POLL_INTERVAL);
748        runTestOnUiThread(new Runnable() {
749            @Override
750            public void run() {
751                assertTrue(updateListener1.wasRunning);
752                assertTrue(updateListener1.startFraction >= 0);
753                assertTrue(updateListener1.startFraction < halfwayFraction);
754                a1.end();
755            }
756        });
757
758    }
759
760    @SmallTest
761    public void testSeekWhileRunning() throws Throwable {
762        // Seek one animator to the beginning and the other one to the end when they are running.
763        final MyListener l1 = new MyListener();
764        final MyListener l2 = new MyListener();
765        a1.addListener(l1);
766        a2.addListener(l2);
767        runTestOnUiThread(new Runnable() {
768            @Override
769            public void run() {
770                assertFalse(l1.startCalled);
771                assertFalse(l2.startCalled);
772                assertEquals(0f, a1.getAnimatedFraction());
773                assertEquals(0f, a2.getAnimatedFraction());
774                a1.start();
775                a2.start();
776            }
777        });
778        Thread.sleep(POLL_INTERVAL);
779        runTestOnUiThread(new Runnable() {
780            @Override
781            public void run() {
782                assertFalse(l1.endCalled);
783                assertFalse(l2.endCalled);
784                assertTrue(a1.isRunning());
785                assertTrue(a2.isRunning());
786                // During the run, seek one to the beginning, the other to the end
787                a1.setCurrentFraction(0f);
788                a2.setCurrentFraction(1f);
789            }
790        });
791        Thread.sleep(POLL_INTERVAL);
792        runTestOnUiThread(new Runnable() {
793            @Override
794            public void run() {
795                // Check that a2 has finished due to the seeking, but a1 hasn't finished.
796                assertFalse(l1.endCalled);
797                assertTrue(l2.endCalled);
798                assertEquals(1f, a2.getAnimatedFraction());
799            }
800        });
801
802        Thread.sleep(a1.getTotalDuration());
803        runTestOnUiThread(new Runnable() {
804            @Override
805            public void run() {
806                // By now a1 should finish also.
807                assertTrue(l1.endCalled);
808                assertEquals(1f, a1.getAnimatedFraction());
809            }
810        });
811    }
812
813    @SmallTest
814    public void testZeroDuration() throws Throwable {
815        // Run two animators with zero duration, with one running forward and the other one
816        // backward. Check that the animations start and finish with the correct end fractions.
817        a1.setDuration(0);
818        a2.setDuration(0);
819
820        // Set a fraction on an animation with 0-duration
821        final ValueAnimator a3 = ValueAnimator.ofInt(0, 100);
822        a3.setDuration(0);
823        a3.setCurrentFraction(1.0f);
824        assertEquals(1.0f, a3.getAnimatedFraction());
825
826        final MyListener l1 = new MyListener();
827        final MyListener l2 = new MyListener();
828        final MyListener l3 = new MyListener();
829        a1.addListener(l1);
830        a2.addListener(l2);
831        a3.addListener(l3);
832        runTestOnUiThread(new Runnable() {
833            @Override
834            public void run() {
835                assertFalse(l1.startCalled);
836                assertFalse(l2.startCalled);
837                assertFalse(l3.startCalled);
838                assertFalse(l1.endCalled);
839                assertFalse(l2.endCalled);
840                assertFalse(l3.endCalled);
841                a1.start();
842                a2.reverse();
843                a3.start();
844            }
845        });
846        Thread.sleep(POLL_INTERVAL);
847        runTestOnUiThread(new Runnable() {
848            @Override
849            public void run() {
850                // Check that the animators have started and finished with the right values.
851                assertTrue(l1.startCalled);
852                assertTrue(l2.startCalled);
853                assertTrue(l3.startCalled);
854                assertTrue(l1.endCalled);
855                assertTrue(l2.endCalled);
856                assertTrue(l3.endCalled);
857                assertEquals(1.0f, a1.getAnimatedFraction());
858                assertEquals(0f, a2.getAnimatedFraction());
859                assertEquals(1f, a3.getAnimatedFraction());
860                assertEquals(A1_END_VALUE, a1.getAnimatedValue());
861                assertEquals(A2_START_VALUE, a2.getAnimatedValue());
862                assertEquals(100, a3.getAnimatedValue());
863            }
864        });
865    }
866
867    @SmallTest
868    public void testZeroScale() throws Throwable {
869        // Test whether animations would end properly when the scale is forced to be zero
870        float scale = ValueAnimator.getDurationScale();
871        ValueAnimator.setDurationScale(0f);
872
873        // Run two animators, one of which has a start delay, after setting the duration scale to 0
874        a1.setStartDelay(200);
875        final MyListener l1 =  new MyListener();
876        final MyListener l2 = new MyListener();
877        a1.addListener(l1);
878        a2.addListener(l2);
879
880        runTestOnUiThread(new Runnable() {
881            @Override
882            public void run() {
883                assertFalse(l1.startCalled);
884                assertFalse(l2.startCalled);
885                assertFalse(l1.endCalled);
886                assertFalse(l2.endCalled);
887
888                a1.start();
889                a2.start();
890            }
891        });
892        Thread.sleep(POLL_INTERVAL);
893
894        runTestOnUiThread(new Runnable() {
895            @Override
896            public void run() {
897                assertTrue(l1.startCalled);
898                assertTrue(l2.startCalled);
899                assertTrue(l1.endCalled);
900                assertTrue(l2.endCalled);
901            }
902        });
903
904        // Restore duration scale
905        ValueAnimator.setDurationScale(scale);
906    }
907
908    @SmallTest
909    public void testReverse() throws Throwable {
910        // Prolong animators duration so that we can do multiple checks during their run
911        final ValueAnimator a3 = ValueAnimator.ofInt(0, 100);
912        a1.setDuration(400);
913        a2.setDuration(600);
914        a3.setDuration(400);
915        final MyListener l1 = new MyListener();
916        final MyListener l2 = new MyListener();
917        final MyListener l3 = new MyListener();
918        a1.addListener(l1);
919        a2.addListener(l2);
920        a3.addListener(l3);
921
922        // Reverse three animators, seek one to the beginning and another to the end, and force
923        // to end the third one during reversing.
924        runTestOnUiThread(new Runnable() {
925            @Override
926            public void run() {
927                assertFalse(l1.startCalled);
928                assertFalse(l2.startCalled);
929                assertFalse(l3.startCalled);
930                assertFalse(l1.endCalled);
931                assertFalse(l2.endCalled);
932                assertFalse(l3.endCalled);
933                a1.reverse();
934                a2.reverse();
935                a3.reverse();
936            }
937        });
938        Thread.sleep(POLL_INTERVAL);
939        runTestOnUiThread(new Runnable() {
940            @Override
941            public void run() {
942                assertTrue(l1.startCalled);
943                assertTrue(l2.startCalled);
944                assertTrue(l3.startCalled);
945
946                a1.setCurrentFraction(0f);
947                a2.setCurrentFraction(1f);
948                a3.end();
949
950                // Check that the fraction has been set, and the getter returns the correct values.
951                assertEquals(1f, a1.getAnimatedFraction());
952                assertEquals(0f, a2.getAnimatedFraction());
953            }
954        });
955        Thread.sleep(POLL_INTERVAL);
956
957        // By now, a2 should have finished due to the seeking. It wouldn't have finished otherwise.
958        runTestOnUiThread(new Runnable() {
959            @Override
960            public void run() {
961                // Check that both animations have started, and a2 has finished.
962                assertFalse(l1.endCalled);
963                assertTrue(l2.endCalled);
964                assertTrue(l3.endCalled);
965            }
966        });
967        Thread.sleep(a1.getTotalDuration());
968
969        runTestOnUiThread(new Runnable() {
970            @Override
971            public void run() {
972                // Verify that a1 has finished as well.
973                assertTrue(l1.endCalled);
974                assertEquals(0f, a1.getAnimatedFraction());
975                assertEquals(0f, a2.getAnimatedFraction());
976                assertEquals(0f, a3.getAnimatedFraction());
977            }
978        });
979    }
980
981    class MyUpdateListener implements ValueAnimator.AnimatorUpdateListener {
982        boolean wasRunning = false;
983        long firstRunningFrameTime = -1;
984        long lastUpdateTime = -1;
985        float startFraction = 0;
986
987        @Override
988        public void onAnimationUpdate(ValueAnimator animation) {
989            lastUpdateTime = SystemClock.uptimeMillis();
990            if (animation.isRunning() && !wasRunning) {
991                // Delay has passed
992                firstRunningFrameTime = lastUpdateTime;
993                startFraction = animation.getAnimatedFraction();
994                wasRunning = animation.isRunning();
995            }
996        }
997
998        void reset() {
999            wasRunning = false;
1000            firstRunningFrameTime = -1;
1001            lastUpdateTime = -1;
1002            startFraction = 0;
1003        }
1004    }
1005
1006    class MyListener implements Animator.AnimatorListener {
1007        boolean startCalled = false;
1008        boolean cancelCalled = false;
1009        boolean endCalled = false;
1010        long startTime = -1;
1011        long endTime = -1;
1012
1013        @Override
1014        public void onAnimationStart(Animator animation) {
1015            startCalled = true;
1016            startTime = SystemClock.uptimeMillis();
1017        }
1018
1019        @Override
1020        public void onAnimationEnd(Animator animation) {
1021            endCalled = true;
1022            endTime = SystemClock.uptimeMillis();
1023        }
1024
1025        @Override
1026        public void onAnimationCancel(Animator animation) {
1027            cancelCalled = true;
1028        }
1029
1030        @Override
1031        public void onAnimationRepeat(Animator animation) {
1032
1033        }
1034    }
1035
1036    class MyPauseListener implements Animator.AnimatorPauseListener {
1037        boolean pauseCalled = false;
1038        boolean resumeCalled = false;
1039
1040        @Override
1041        public void onAnimationPause(Animator animation) {
1042            pauseCalled = true;
1043        }
1044
1045        @Override
1046        public void onAnimationResume(Animator animation) {
1047            resumeCalled = true;
1048        }
1049    }
1050
1051    class MyFrameCallbackProvider implements AnimationHandler.AnimationFrameCallbackProvider {
1052
1053        Handler mHandler = null;
1054        private final static int MSG_FRAME = 0;
1055        private long mFrameDelay = DEFAULT_FRAME_INTERVAL;
1056        private ArrayList<Choreographer.FrameCallback> mFrameCallbacks = new ArrayList<>();
1057
1058        final LooperThread mThread = new LooperThread();
1059
1060        public MyFrameCallbackProvider() {
1061            mThread.start();
1062        }
1063
1064        @Override
1065        public void postFrameCallback(Choreographer.FrameCallback callback) {
1066            mHandler.sendEmptyMessageDelayed(MSG_FRAME, mFrameDelay);
1067            if (!mFrameCallbacks.contains(callback)) {
1068                mFrameCallbacks.add(callback);
1069            }
1070        }
1071
1072        @Override
1073        public void postCommitCallback(Runnable runnable) {
1074            // Run the runnable after a commit delay
1075            mHandler.postDelayed(runnable, COMMIT_DELAY);
1076        }
1077
1078        @Override
1079        public long getFrameTime() {
1080            return SystemClock.uptimeMillis();
1081        }
1082
1083        @Override
1084        public long getFrameDelay() {
1085            return mFrameDelay;
1086        }
1087
1088        @Override
1089        public void setFrameDelay(long delay) {
1090            mFrameDelay = delay;
1091            if (mFrameCallbacks.size() != 0) {
1092                mHandler.removeMessages(MSG_FRAME);
1093                mHandler.sendEmptyMessageDelayed(MSG_FRAME, mFrameDelay);
1094            }
1095        }
1096
1097        class LooperThread extends Thread {
1098            public void run() {
1099                Looper.prepare();
1100                mHandler = new Handler() {
1101                    public void handleMessage(Message msg) {
1102                        // Handle message here.
1103                        switch (msg.what) {
1104                            case MSG_FRAME:
1105                                for (int i = 0; i < mFrameCallbacks.size(); i++) {
1106                                    mFrameCallbacks.get(i).doFrame(SystemClock.uptimeMillis());
1107                                }
1108                                break;
1109                            default:
1110                                break;
1111                        }
1112                    }
1113                };
1114                Looper.loop();
1115            }
1116        }
1117    }
1118}
1119