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 76 public void setup() { 77 InstrumentationRegistry.getInstrumentation().setInTouchMode(false); 78 mActivity = mActivityRule.getActivity(); 79 mValueAnimator = mActivity.createAnimatorWithDuration(mDuration); 80 } 81 82 @BeforeClass 83 public static void beforeClass() { 84 sPreviousAnimatorScale = ValueAnimator.getDurationScale(); 85 ValueAnimator.setDurationScale(1.0f); 86 } 87 88 @AfterClass 89 public static void afterClass() { 90 ValueAnimator.setDurationScale(sPreviousAnimatorScale); 91 } 92 93 @Test 94 public void testDuration() throws Throwable { 95 ValueAnimator valueAnimatorLocal = mActivity.createAnimatorWithDuration(mDuration); 96 startAnimation(valueAnimatorLocal); 97 assertEquals(mDuration, valueAnimatorLocal.getDuration()); 98 } 99 100 @Test 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 459 public void testCancel() throws Throwable { 460 startAnimation(mValueAnimator); 461 SystemClock.sleep(100); 462 cancelAnimation(mValueAnimator); 463 assertFalse(mValueAnimator.isRunning()); 464 } 465 466 @Test 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 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 520 public float getInterpolation(float input) { 521 return input * input; 522 } 523 } 524 525 @Test 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 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 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 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 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 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 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 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 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 742 private void startAnimation(final ValueAnimator animator) throws Throwable { 743 mActivityRule.runOnUiThread(() -> mActivity.startAnimation(animator)); 744 } 745 746 private void endAnimation(final ValueAnimator animator) throws Throwable { 747 mActivityRule.runOnUiThread(animator::end); 748 } 749 750 private void cancelAnimation(final ValueAnimator animator) throws Throwable { 751 mActivityRule.runOnUiThread(animator::cancel); 752 } 753 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