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