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.assertNotNull;
23 import static org.junit.Assert.assertTrue;
24 import static org.mockito.Mockito.atLeast;
25 import static org.mockito.Mockito.mock;
26 import static org.mockito.Mockito.timeout;
27 import static org.mockito.Mockito.times;
28 import static org.mockito.Mockito.verify;
29 
30 import android.animation.Animator;
31 import android.animation.Animator.AnimatorListener;
32 import android.animation.AnimatorListenerAdapter;
33 import android.animation.ObjectAnimator;
34 import android.animation.PropertyValuesHolder;
35 import android.animation.TimeInterpolator;
36 import android.animation.TypeEvaluator;
37 import android.animation.ValueAnimator;
38 import android.animation.ValueAnimator.AnimatorUpdateListener;
39 import android.graphics.Color;
40 import android.graphics.PointF;
41 import android.os.SystemClock;
42 import android.view.animation.AccelerateInterpolator;
43 import android.view.animation.LinearInterpolator;
44 
45 import androidx.test.InstrumentationRegistry;
46 import androidx.test.annotation.UiThreadTest;
47 import androidx.test.filters.LargeTest;
48 import androidx.test.rule.ActivityTestRule;
49 import androidx.test.runner.AndroidJUnit4;
50 
51 import org.junit.AfterClass;
52 import org.junit.Before;
53 import org.junit.BeforeClass;
54 import org.junit.Rule;
55 import org.junit.Test;
56 import org.junit.runner.RunWith;
57 
58 import java.util.concurrent.CountDownLatch;
59 import java.util.concurrent.TimeUnit;
60 
61 @LargeTest
62 @RunWith(AndroidJUnit4.class)
63 public class ValueAnimatorTest {
64     private static final float EPSILON = 0.0001f;
65     private static float sPreviousAnimatorScale = 1.0f;
66 
67     private AnimationActivity mActivity;
68     private ValueAnimator mValueAnimator;
69     private final long mDuration = 2000;
70 
71     @Rule
72     public ActivityTestRule<AnimationActivity> mActivityRule =
73             new ActivityTestRule<>(AnimationActivity.class);
74 
75     @Before
setup()76     public void setup() {
77         InstrumentationRegistry.getInstrumentation().setInTouchMode(false);
78         mActivity = mActivityRule.getActivity();
79         mValueAnimator = mActivity.createAnimatorWithDuration(mDuration);
80     }
81 
82     @BeforeClass
beforeClass()83     public static void beforeClass() {
84         sPreviousAnimatorScale = ValueAnimator.getDurationScale();
85         ValueAnimator.setDurationScale(1.0f);
86     }
87 
88     @AfterClass
afterClass()89     public static void afterClass() {
90         ValueAnimator.setDurationScale(sPreviousAnimatorScale);
91     }
92 
93     @Test
testDuration()94     public void testDuration() throws Throwable {
95         ValueAnimator valueAnimatorLocal = mActivity.createAnimatorWithDuration(mDuration);
96         startAnimation(valueAnimatorLocal);
97         assertEquals(mDuration, valueAnimatorLocal.getDuration());
98     }
99 
100     @Test
testIsRunning()101     public void testIsRunning() throws Throwable {
102         assertFalse(mValueAnimator.isRunning());
103         startAnimation(mValueAnimator);
104         ValueAnimator valueAnimatorReturned = mActivity.view.bounceYAnimator;
105         assertTrue(valueAnimatorReturned.isRunning());
106     }
107 
108     @Test
testIsStarted()109     public void testIsStarted() throws Throwable {
110         assertFalse(mValueAnimator.isRunning());
111         assertFalse(mValueAnimator.isStarted());
112         long startDelay = 10000;
113         mValueAnimator.setStartDelay(startDelay);
114         startAnimation(mValueAnimator);
115         assertFalse(mValueAnimator.isRunning());
116         assertTrue(mValueAnimator.isStarted());
117     }
118 
119     @Test
testRepeatMode()120     public void testRepeatMode() throws Throwable {
121         ValueAnimator mValueAnimator = mActivity.createAnimatorWithRepeatMode(
122             ValueAnimator.RESTART);
123         startAnimation(mValueAnimator);
124         assertEquals(ValueAnimator.RESTART, mValueAnimator.getRepeatMode());
125     }
126 
127     @Test
testRepeatCount()128     public void testRepeatCount() throws Throwable {
129         int repeatCount = 2;
130         ValueAnimator mValueAnimator = mActivity.createAnimatorWithRepeatCount(repeatCount);
131         startAnimation(mValueAnimator);
132         assertEquals(repeatCount, mValueAnimator.getRepeatCount());
133     }
134 
135     @Test
testStartDelay()136     public void testStartDelay() {
137         long startDelay = 1000;
138         mValueAnimator.setStartDelay(startDelay);
139         assertEquals(startDelay, mValueAnimator.getStartDelay());
140     }
141 
142     /**
143      * Verify that an animator with start delay will have its listener's onAnimationStart(...)
144      * and onAnimationEnd(...) called at the right time.
145      */
146     @Test
testListenerCallbackWithStartDelay()147     public void testListenerCallbackWithStartDelay() throws Throwable {
148         final ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
149         anim.setStartDelay(300);
150         anim.setDuration(300);
151         AnimatorListener listener = mock(AnimatorListenerAdapter.class);
152         anim.addListener(listener);
153         mActivityRule.runOnUiThread(() -> {
154             anim.start();
155         });
156 
157         verify(listener, timeout(450).times(1)).onAnimationStart(anim, false);
158         verify(listener, timeout(450).times(1)).onAnimationEnd(anim, false);
159     }
160 
161     @Test
testGetCurrentPlayTime()162     public void testGetCurrentPlayTime() throws Throwable {
163         startAnimation(mValueAnimator);
164         SystemClock.sleep(100);
165         long currentPlayTime = mValueAnimator.getCurrentPlayTime();
166         assertTrue(currentPlayTime  >  0);
167     }
168 
169     @Test
testSetCurrentPlayTime()170     public void testSetCurrentPlayTime() throws Throwable {
171         final ValueAnimator anim = ValueAnimator.ofFloat(0, 100).setDuration(mDuration);
172         final ValueAnimator delayedAnim = ValueAnimator.ofFloat(0, 100).setDuration(mDuration);
173         delayedAnim.setStartDelay(mDuration);
174         final long proposedCurrentPlayTime = mDuration / 2;
175         mActivityRule.runOnUiThread(() -> {
176             anim.setCurrentPlayTime(mDuration / 2);
177             long currentPlayTime = anim.getCurrentPlayTime();
178             float currentFraction = anim.getAnimatedFraction();
179             float currentValue = (Float) anim.getAnimatedValue();
180             assertEquals(proposedCurrentPlayTime, currentPlayTime);
181             assertEquals(.5f, currentFraction, EPSILON);
182             assertEquals(50, currentValue, EPSILON);
183 
184             delayedAnim.setCurrentPlayTime(mDuration / 2);
185             currentPlayTime = delayedAnim.getCurrentPlayTime();
186             currentFraction = delayedAnim.getAnimatedFraction();
187             currentValue = (Float) delayedAnim.getAnimatedValue();
188             assertEquals(proposedCurrentPlayTime, currentPlayTime);
189             assertEquals(.5f, currentFraction, EPSILON);
190             assertEquals(50, currentValue, EPSILON);
191         });
192         // Now make sure that it's still true a little later, to test that we're
193         // getting a result based on the seek time, not the wall clock time
194         SystemClock.sleep(100);
195         long currentPlayTime = anim.getCurrentPlayTime();
196         float currentFraction = anim.getAnimatedFraction();
197         float currentValue = (Float) anim.getAnimatedValue();
198         assertEquals(proposedCurrentPlayTime, currentPlayTime);
199         assertEquals(.5f, currentFraction, EPSILON);
200         assertEquals(50, currentValue, EPSILON);
201 
202         currentPlayTime = delayedAnim.getCurrentPlayTime();
203         currentFraction = delayedAnim.getAnimatedFraction();
204         currentValue = (Float) delayedAnim.getAnimatedValue();
205         assertEquals(proposedCurrentPlayTime, currentPlayTime);
206         assertEquals(.5f, currentFraction, EPSILON);
207         assertEquals(50, currentValue, EPSILON);
208 
209         // Finally, start() the delayed animation and check that the play time was
210         // not affected by playing during the delay
211         mActivityRule.runOnUiThread(() -> {
212             delayedAnim.start();
213             assertEquals(proposedCurrentPlayTime, delayedAnim.getCurrentPlayTime());
214             assertEquals(.5f, delayedAnim.getAnimatedFraction(), EPSILON);
215             assertEquals(50, (float) delayedAnim.getAnimatedValue(), EPSILON);
216         });
217 
218         SystemClock.sleep(100);
219         currentPlayTime = delayedAnim.getCurrentPlayTime();
220         currentFraction = delayedAnim.getAnimatedFraction();
221         currentValue = (Float) delayedAnim.getAnimatedValue();
222         assertTrue(currentPlayTime > proposedCurrentPlayTime);
223         assertTrue(currentFraction > 0.5f);
224         assertTrue(currentValue > 50);
225 
226         mActivityRule.runOnUiThread(delayedAnim::cancel);
227     }
228 
229     @Test
testPauseListener()230     public void testPauseListener() throws Throwable {
231         // Adds two pause listeners to the animator, and remove one after the animator is paused.
232         Animator.AnimatorPauseListener l1 = mock(Animator.AnimatorPauseListener.class);
233         Animator.AnimatorPauseListener l2 = mock(Animator.AnimatorPauseListener.class);
234         ValueAnimator a1 = ValueAnimator.ofFloat(0, 1f);
235         a1.addPauseListener(l1);
236         a1.addPauseListener(l2);
237         mActivityRule.runOnUiThread(() -> {
238             a1.start();
239             a1.pause();
240             verify(l1, times(1)).onAnimationPause(a1);
241             verify(l2, times(1)).onAnimationPause(a1);
242             a1.removePauseListener(l2);
243             a1.resume();
244         });
245 
246         // Check that the pause listener that is removed doesn't have resume called.
247         verify(l1, times(1)).onAnimationResume(a1);
248         verify(l2, times(0)).onAnimationResume(a1);
249     }
250 
251     @Test
testSetCurrentPlayTimeAfterStart()252     public void testSetCurrentPlayTimeAfterStart() throws Throwable {
253         // This test sets current play time right after start() is called on a non-delayed animation
254         final long duration = 100;
255         final float seekFraction = 0.2f;
256         final CountDownLatch frameUpdateLatch = new CountDownLatch(1);
257 
258         final AnimatorSetTest.MyListener myListener = new AnimatorSetTest.MyListener();
259         final ValueAnimator anim  = ValueAnimator.ofFloat(0, 1).setDuration(duration);
260         anim.setInterpolator(null);
261         final Animator.AnimatorListener listener = mock(Animator.AnimatorListener.class);
262         anim.addListener(listener);
263         anim.addListener(myListener);
264         mActivityRule.runOnUiThread(() -> {
265             anim.start();
266             anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
267                 float fractionOnFirstFrame = -1f;
268 
269                 @Override
270                 public void onAnimationUpdate(ValueAnimator animation) {
271                     if (fractionOnFirstFrame < 0) {
272                         // First frame:
273                         fractionOnFirstFrame = animation.getAnimatedFraction();
274                         assertEquals(seekFraction, fractionOnFirstFrame, EPSILON);
275                         frameUpdateLatch.countDown();
276                     } else {
277                         assertTrue(animation.getAnimatedFraction() >= fractionOnFirstFrame);
278                     }
279                 }
280             });
281             long currentPlayTime = (long) (seekFraction * (float) duration);
282             anim.setCurrentPlayTime(currentPlayTime);
283         });
284         assertTrue(frameUpdateLatch.await(100, TimeUnit.MILLISECONDS));
285         verify(listener, within(200)).onAnimationEnd(anim, false);
286         // Also make sure the onAnimationEnd(anim) is called.
287         assertTrue(myListener.mEndIsCalled);
288     }
289 
290     @Test
testSetCurrentFraction()291     public void testSetCurrentFraction() throws Throwable {
292         final ValueAnimator anim = ValueAnimator.ofFloat(0, 100).setDuration(mDuration);
293         final long proposedCurrentPlayTime = mDuration / 2;
294         mActivityRule.runOnUiThread(() -> {
295             anim.setCurrentFraction(.5f);
296             long currentPlayTime = anim.getCurrentPlayTime();
297             float currentFraction = anim.getAnimatedFraction();
298             float currentValue = (Float) anim.getAnimatedValue();
299             assertEquals(proposedCurrentPlayTime, currentPlayTime);
300             assertEquals(.5f, currentFraction, EPSILON);
301             assertEquals(50, currentValue, EPSILON);
302         });
303         // Now make sure that it's still true a little later, to test that we're
304         // getting a result based on the seek time, not the wall clock time
305         SystemClock.sleep(100);
306         long currentPlayTime = anim.getCurrentPlayTime();
307         float currentFraction = anim.getAnimatedFraction();
308         float currentValue = (Float) anim.getAnimatedValue();
309         assertEquals(proposedCurrentPlayTime, currentPlayTime);
310         assertEquals(.5f, currentFraction, EPSILON);
311         assertEquals(50, currentValue, EPSILON);
312     }
313 
314     @UiThreadTest
315     @Test
testReverseRightAfterStart()316     public void testReverseRightAfterStart() {
317         // Reverse() right after start() should trigger immediate end() at fraction 0.
318         final ValueAnimator anim = ValueAnimator.ofFloat(0, 100).setDuration(mDuration);
319         anim.start();
320         assertTrue(anim.isStarted());
321         anim.reverse();
322         assertFalse(anim.isStarted());
323         assertEquals(0f, anim.getAnimatedFraction(), 0.0f);
324     }
325 
326     @Test
testGetFrameDelay()327     public void testGetFrameDelay() throws Throwable {
328         final long frameDelay = 10;
329         mActivityRule.runOnUiThread(() -> mValueAnimator.setFrameDelay(frameDelay));
330         startAnimation(mValueAnimator);
331         SystemClock.sleep(100);
332         mActivityRule.runOnUiThread(() -> {
333             long actualFrameDelay = mValueAnimator.getFrameDelay();
334             assertEquals(frameDelay, actualFrameDelay);
335         });
336     }
337 
338     @Test
testUpdateListeners()339     public void testUpdateListeners() throws Throwable {
340         final AnimatorSetTest.MyListener myListener = new AnimatorSetTest.MyListener();
341         ValueAnimator.AnimatorUpdateListener l1 = mock(ValueAnimator.AnimatorUpdateListener.class);
342         ValueAnimator.AnimatorUpdateListener l2 = mock(ValueAnimator.AnimatorUpdateListener.class);
343         ValueAnimator.AnimatorUpdateListener l3 = mock(ValueAnimator.AnimatorUpdateListener.class);
344         ValueAnimator.AnimatorUpdateListener l4 = mock(ValueAnimator.AnimatorUpdateListener.class);
345 
346         AnimatorListenerAdapter listener = mock(AnimatorListenerAdapter.class);
347 
348         ValueAnimator a1 = ValueAnimator.ofFloat(0, 1f);
349         a1.setDuration(50);
350         a1.addUpdateListener(l1);
351         a1.addUpdateListener(l2);
352         a1.removeAllUpdateListeners();
353 
354         a1.addUpdateListener(l3);
355         a1.addUpdateListener(l4);
356         a1.removeUpdateListener(l3);
357 
358         a1.addListener(listener);
359         a1.addListener(myListener);
360 
361         mActivityRule.runOnUiThread(() -> {
362             a1.start();
363         });
364 
365         // Wait for the anim to finish.
366         verify(listener, within(200)).onAnimationEnd(a1, false);
367         // Also make sure the onAnimationEnd(anim) is called.
368         assertTrue(myListener.mEndIsCalled);
369 
370         verify(l1, times(0)).onAnimationUpdate(a1);
371         verify(l2, times(0)).onAnimationUpdate(a1);
372         verify(l3, times(0)).onAnimationUpdate(a1);
373         verify(l4, atLeast(1)).onAnimationUpdate(a1);
374     }
375 
376     @Test
testValuesSetterAndGetter()377     public void testValuesSetterAndGetter() throws Throwable {
378 
379         final AnimatorSetTest.MyListener myListener = new AnimatorSetTest.MyListener();
380         ValueAnimator a2 = ValueAnimator.ofPropertyValuesHolder();
381         PropertyValuesHolder p1 = PropertyValuesHolder.ofFloat("scaleX", 0f, 1f);
382         PropertyValuesHolder p2 = PropertyValuesHolder.ofFloat("scaleY", 1f, 2f);
383         a2.setValues(p1, p2);
384         PropertyValuesHolder[] holders = a2.getValues();
385         assertEquals(2, holders.length);
386 
387         // Use the PropertyValueHolders returned from the getter to initialize the animator, in
388         // order to test the getter.
389         ValueAnimator a1 = ValueAnimator.ofPropertyValuesHolder(holders);
390         a1.setDuration(50);
391         a1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
392             @Override
393             public void onAnimationUpdate(ValueAnimator animation) {
394                 float scaleX = (Float) animation.getAnimatedValue("scaleX");
395                 float scaleY = (Float) animation.getAnimatedValue("scaleY");
396                 assertTrue(scaleX >= 0f && scaleX <= 1f);
397                 assertTrue(scaleY >= 1f && scaleY <= 2f);
398             }
399         });
400         AnimatorListenerAdapter l1 = mock(AnimatorListenerAdapter.class);
401         a1.addListener(l1);
402         a1.addListener(myListener);
403 
404         mActivityRule.runOnUiThread(() -> {
405             a1.start();
406         });
407 
408         verify(l1, within(200)).onAnimationEnd(a1, false);
409         // Also make sure the onAnimationEnd(anim) is called.
410         assertTrue(myListener.mEndIsCalled);
411     }
412 
413     @Test
testSetObjectValues()414     public void testSetObjectValues() throws Throwable {
415         TypeEvaluator<PointF> eval = new TypeEvaluator<PointF>() {
416             PointF tmpValue = new PointF();
417             @Override
418             public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
419                 tmpValue.x = fraction * startValue.x + (1f - fraction) * endValue.x;
420                 tmpValue.y = fraction * startValue.y + (1f - fraction) * endValue.y;
421                 return tmpValue;
422             }
423         };
424 
425         final AnimatorSetTest.MyListener myListener = new AnimatorSetTest.MyListener();
426         ValueAnimator a1 = new ValueAnimator();
427         a1.setDuration(50);
428         a1.setObjectValues(new PointF(0, 0), new PointF(1, 1));
429         a1.setEvaluator(eval);
430         a1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
431             @Override
432             public void onAnimationUpdate(ValueAnimator animation) {
433                 PointF point = (PointF) animation.getAnimatedValue();
434                 assertTrue(point.x >= 0f && point.x <= 1f);
435                 assertTrue(point.y >= 0f && point.y <= 1f);
436             }
437         });
438         AnimatorListenerAdapter l1 = mock(AnimatorListenerAdapter.class);
439         a1.addListener(l1);
440         a1.addListener(myListener);
441         mActivityRule.runOnUiThread(() -> {
442             a1.start();
443         });
444 
445         verify(l1, within(200)).onAnimationEnd(a1, false);
446         // Also make sure the onAnimationEnd(anim) is called.
447         assertTrue(myListener.mEndIsCalled);
448     }
449 
450     @Test
testSetInterpolator()451     public void testSetInterpolator() throws Throwable {
452         AccelerateInterpolator interpolator = new AccelerateInterpolator();
453         ValueAnimator mValueAnimator = mActivity.createAnimatorWithInterpolator(interpolator);
454         startAnimation(mValueAnimator);
455         assertTrue(interpolator.equals(mValueAnimator.getInterpolator()));
456     }
457 
458     @Test
testCancel()459     public void testCancel() throws Throwable {
460         startAnimation(mValueAnimator);
461         SystemClock.sleep(100);
462         cancelAnimation(mValueAnimator);
463         assertFalse(mValueAnimator.isRunning());
464     }
465 
466     @Test
testEnd()467     public void testEnd() throws Throwable {
468         Object object = mActivity.view.newBall;
469         String property = "y";
470         float startY = mActivity.mStartY;
471         float endY = mActivity.mStartY + mActivity.mDeltaY;
472         ObjectAnimator objAnimator = ObjectAnimator.ofFloat(object, property, startY, endY);
473         objAnimator.setDuration(mDuration);
474         objAnimator.setRepeatCount(ValueAnimator.INFINITE);
475         objAnimator.setInterpolator(new AccelerateInterpolator());
476         objAnimator.setRepeatMode(ValueAnimator.REVERSE);
477         startAnimation(objAnimator);
478         SystemClock.sleep(100);
479         endAnimation(objAnimator);
480         float y = mActivity.view.newBall.getY();
481         assertEquals(y, endY, 0.0f);
482     }
483 
484     @Test
testGetAnimatedFraction()485     public void testGetAnimatedFraction() throws Throwable {
486         ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
487         assertNotNull(animator);
488         animator.setDuration(200);
489         animator.addUpdateListener(new AnimatorUpdateListener() {
490             public float lastFraction = 0;
491             @Override
492             public void onAnimationUpdate(ValueAnimator animation) {
493                 float currentFraction = animation.getAnimatedFraction();
494                 assertTrue(
495                         "Last fraction = " + lastFraction + "current fraction = " + currentFraction,
496                         animation.getAnimatedFraction() >= lastFraction);
497                 lastFraction = currentFraction;
498                 assertTrue(currentFraction <= 1f);
499             }
500         });
501         CountDownLatch latch = new CountDownLatch(1);
502         animator.addListener(new AnimatorListenerAdapter() {
503             @Override
504             public void onAnimationEnd(Animator animation) {
505                 latch.countDown();
506             }
507         });
508         mActivityRule.runOnUiThread(() -> {
509             animator.start();
510         });
511 
512         latch.await(1000, TimeUnit.MILLISECONDS);
513 
514         assertEquals(1.0f, animator.getAnimatedFraction(), EPSILON);
515     }
516 
517     class TestInterpolator implements TimeInterpolator {
518 
519         @Override
getInterpolation(float input)520         public float getInterpolation(float input) {
521             return input * input;
522         }
523     }
524 
525     @Test
testGetAnimatedValue()526     public void testGetAnimatedValue() {
527         ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
528         assertNotNull(animator);
529         TimeInterpolator myInterpolator = new TestInterpolator();
530         animator.setInterpolator(myInterpolator);
531         int sliceNum = 10;
532         for (int i = 0; i <= sliceNum; i++) {
533             float fraction = i / (float) sliceNum;
534             animator.setCurrentFraction(fraction);
535             assertEquals(myInterpolator.getInterpolation(fraction),
536                     (float) animator.getAnimatedValue(), EPSILON);
537 
538         }
539     }
540 
541     @Test
testGetAnimatedValue_PropertyName()542     public void testGetAnimatedValue_PropertyName() {
543         PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 100f, -100f);
544         PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 0f, 1f);
545         ValueAnimator animator = ValueAnimator.ofPropertyValuesHolder(pvhX, pvhY);
546         assertNotNull(animator);
547         TimeInterpolator myInterpolator = new TestInterpolator();
548         animator.setInterpolator(myInterpolator);
549         int sliceNum = 10;
550         for (int i = 0; i <= sliceNum; i++) {
551             float fraction = i / (float) sliceNum;
552             animator.setCurrentFraction(fraction);
553             assertEquals(myInterpolator.getInterpolation(fraction),
554                     (float) animator.getAnimatedValue("y"), EPSILON);
555 
556         }
557     }
558 
559     @Test
testOfFloat()560     public void testOfFloat() throws Throwable {
561         float start = 0.0f;
562         float end = 1.0f;
563         float[] values = {start, end};
564         final ValueAnimator valueAnimatorLocal = ValueAnimator.ofFloat(values);
565         valueAnimatorLocal.setDuration(mDuration);
566         valueAnimatorLocal.setRepeatCount(ValueAnimator.INFINITE);
567         valueAnimatorLocal.setInterpolator(new AccelerateInterpolator());
568         valueAnimatorLocal.setRepeatMode(ValueAnimator.RESTART);
569 
570         mActivityRule.runOnUiThread(valueAnimatorLocal::start);
571         SystemClock.sleep(100);
572         boolean isRunning = valueAnimatorLocal.isRunning();
573         assertTrue(isRunning);
574 
575         Float animatedValue = (Float) valueAnimatorLocal.getAnimatedValue();
576         assertTrue(animatedValue >= start);
577         assertTrue(animatedValue <= end);
578     }
579 
580     @Test
testOfInt()581     public void testOfInt() throws Throwable {
582         int start = 0;
583         int end = 10;
584         int[] values = {start, end};
585         final ValueAnimator valueAnimatorLocal = ValueAnimator.ofInt(values);
586         valueAnimatorLocal.setDuration(mDuration);
587         valueAnimatorLocal.setRepeatCount(ValueAnimator.INFINITE);
588         valueAnimatorLocal.setInterpolator(new AccelerateInterpolator());
589         valueAnimatorLocal.setRepeatMode(ValueAnimator.RESTART);
590 
591         mActivityRule.runOnUiThread(valueAnimatorLocal::start);
592         SystemClock.sleep(100);
593         boolean isRunning = valueAnimatorLocal.isRunning();
594         assertTrue(isRunning);
595 
596         Integer animatedValue = (Integer) valueAnimatorLocal.getAnimatedValue();
597         assertTrue(animatedValue >= start);
598         assertTrue(animatedValue <= end);
599     }
600 
601     @Test
testOfArgb()602     public void testOfArgb() throws Throwable {
603         int start = 0xffff0000;
604         int end = 0xff0000ff;
605         int[] values = {start, end};
606         int startRed = Color.red(start);
607         int startBlue = Color.blue(start);
608         int endRed = Color.red(end);
609         int endBlue = Color.blue(end);
610         final ValueAnimator valueAnimatorLocal = ValueAnimator.ofArgb(values);
611         valueAnimatorLocal.setDuration(mDuration);
612 
613         final CountDownLatch latch = new CountDownLatch(1);
614         valueAnimatorLocal.addUpdateListener((ValueAnimator animation) -> {
615             if (animation.getAnimatedFraction() > .05f) {
616                 latch.countDown();
617             }
618         });
619 
620         mActivityRule.runOnUiThread(valueAnimatorLocal::start);
621         boolean isRunning = valueAnimatorLocal.isRunning();
622         assertTrue(isRunning);
623 
624         assertTrue(latch.await(500, TimeUnit.MILLISECONDS));
625 
626         Integer animatedValue = (Integer) valueAnimatorLocal.getAnimatedValue();
627         int alpha = Color.alpha(animatedValue);
628         int red = Color.red(animatedValue);
629         int green = Color.green(animatedValue);
630         int blue = Color.blue(animatedValue);
631         assertTrue(red < startRed);
632         assertTrue(red > endRed);
633         assertTrue(blue > startBlue);
634         assertTrue(blue < endBlue);
635         assertEquals(255, alpha);
636         assertEquals(0, green);
637 
638         mActivityRule.runOnUiThread(valueAnimatorLocal::cancel);
639     }
640 
641     @Test
642     public void testNoDelayOnSeekAnimation() throws Throwable {
643         ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
644         animator.setInterpolator(new LinearInterpolator());
645         animator.setStartDelay(1000);
646         animator.setDuration(300);
647         animator.setCurrentPlayTime(150);
648         final Animator.AnimatorListener watcher = mock(Animator.AnimatorListener.class);
649         animator.addListener(watcher);
650         mActivityRule.runOnUiThread(animator::start);
651         verify(watcher, times(1)).onAnimationStart(animator, false);
652         assertTrue(((Float)animator.getAnimatedValue()) >= 0.5f);
653         assertTrue(animator.getAnimatedFraction() >= 0.5f);
654         mActivityRule.runOnUiThread(animator::cancel);
655     }
656 
657     @Test
testNotifiesAfterEnd()658     public void testNotifiesAfterEnd() throws Throwable {
659         final ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
660         animator.addListener(new AnimatorListenerAdapter() {
661             @Override
662             public void onAnimationStart(Animator animation) {
663                 assertTrue(animation.isStarted());
664                 assertTrue(animation.isRunning());
665             }
666 
667             @Override
668             public void onAnimationEnd(Animator animation) {
669                 assertFalse(animation.isRunning());
670                 assertFalse(animation.isStarted());
671                 super.onAnimationEnd(animation);
672             }
673         });
674         mActivityRule.runOnUiThread(() -> {
675             animator.start();
676             animator.end();
677         });
678     }
679 
680     @Test
testAnimatorsEnabled()681     public void testAnimatorsEnabled() throws Throwable {
682         float currentDurationScale = ValueAnimator.getDurationScale();
683         try {
684             testAnimatorsEnabledImpl(true);
685             testAnimatorsEnabledImpl(false);
686         } finally {
687             // restore scale value to avoid messing up future tests
688             ValueAnimator.setDurationScale(currentDurationScale);
689         }
690     }
691 
testAnimatorsEnabledImpl(boolean enabled)692     private void testAnimatorsEnabledImpl(boolean enabled) throws Throwable {
693         final CountDownLatch startLatch = new CountDownLatch(1);
694         final CountDownLatch endLatch = new CountDownLatch(1);
695         final ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
696         animator.setDuration(1000);
697         animator.addListener(new AnimatorListenerAdapter() {
698             @Override
699             public void onAnimationEnd(Animator animation) {
700                 endLatch.countDown();
701             }
702         });
703         mActivityRule.runOnUiThread(() -> {
704             animator.start();
705             startLatch.countDown();
706         });
707 
708         assertTrue(startLatch.await(200, TimeUnit.MILLISECONDS));
709 
710         float durationScale = enabled ? 1 : 0;
711         ValueAnimator.setDurationScale(durationScale);
712 
713         if (enabled) {
714             assertTrue("Animators not enabled with duration scale 1",
715                     ValueAnimator.areAnimatorsEnabled());
716             assertFalse("Animator ended too early when animators enabled = ",
717                     endLatch.await(100, TimeUnit.MILLISECONDS));
718         } else {
719             assertFalse("Animators enabled with duration scale 0",
720                     ValueAnimator.areAnimatorsEnabled());
721             assertTrue("Animator did not end when animators enabled = ",
722                     endLatch.await(100, TimeUnit.MILLISECONDS));
723         }
724         mActivityRule.runOnUiThread(() -> {
725             animator.end();
726         });
727     }
728 
getAnimator()729     private ValueAnimator getAnimator() {
730         Object object = mActivity.view.newBall;
731         String property = "y";
732         float startY = mActivity.mStartY;
733         float endY = mActivity.mStartY + mActivity.mDeltaY;
734         ValueAnimator objAnimator = ObjectAnimator.ofFloat(object, property, startY, endY);
735         objAnimator.setDuration(mDuration);
736         objAnimator.setRepeatCount(ValueAnimator.INFINITE);
737         objAnimator.setInterpolator(new AccelerateInterpolator());
738         objAnimator.setRepeatMode(ValueAnimator.REVERSE);
739         return objAnimator;
740     }
741 
startAnimation(final ValueAnimator animator)742     private void startAnimation(final ValueAnimator animator) throws Throwable {
743         mActivityRule.runOnUiThread(() -> mActivity.startAnimation(animator));
744     }
745 
endAnimation(final ValueAnimator animator)746     private void endAnimation(final ValueAnimator animator) throws Throwable {
747         mActivityRule.runOnUiThread(animator::end);
748     }
749 
cancelAnimation(final ValueAnimator animator)750     private void cancelAnimation(final ValueAnimator animator) throws Throwable {
751         mActivityRule.runOnUiThread(animator::cancel);
752     }
753 
errorMessage(float[] values)754     private String errorMessage(float[] values) {
755         StringBuilder message = new StringBuilder();
756         for (int i = 0; i < values.length; i++) {
757             message.append(values[i]).append(" ");
758         }
759         return message.toString();
760     }
761 }
762