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