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 runTestOnUiThread(new Runnable() { 332 @Override 333 public void run() { 334 a1.resume(); 335 } 336 }); 337 338 Thread.sleep(a1.getTotalDuration()); 339 340 assertTrue(l1.pauseCalled); 341 assertTrue(l1.resumeCalled); 342 assertFalse(l2.pauseCalled); 343 assertFalse(l2.resumeCalled); 344 } 345 346 @SmallTest 347 public void testResume() throws Throwable { 348 final MyUpdateListener l1 = new MyUpdateListener(); 349 final long totalDuration = a1.getTotalDuration(); 350 a1.addUpdateListener(l1); 351 // Set a longer duration on a1 for this test 352 a1.setDuration(1000); 353 assertTrue(l1.firstRunningFrameTime < 0); 354 assertTrue(l1.lastUpdateTime < 0); 355 356 final long[] lastUpdate = new long[1]; 357 358 runTestOnUiThread(new Runnable() { 359 @Override 360 public void run() { 361 a1.start(); 362 } 363 }); 364 365 Thread.sleep(totalDuration / 2); 366 367 runTestOnUiThread(new Runnable() { 368 @Override 369 public void run() { 370 assertTrue(l1.firstRunningFrameTime > 0); 371 assertTrue(l1.lastUpdateTime > l1.firstRunningFrameTime); 372 lastUpdate[0] = l1.lastUpdateTime; 373 a1.pause(); 374 } 375 }); 376 377 Thread.sleep(totalDuration); 378 379 runTestOnUiThread(new Runnable() { 380 @Override 381 public void run() { 382 // There should be no update after pause() 383 assertEquals(lastUpdate[0], l1.lastUpdateTime); 384 a1.resume(); 385 } 386 }); 387 388 do { 389 Thread.sleep(POLL_INTERVAL); 390 runTestOnUiThread(new Runnable() { 391 @Override 392 public void run() { 393 assertTrue(l1.lastUpdateTime > lastUpdate[0]); 394 lastUpdate[0] = l1.lastUpdateTime; 395 } 396 }); 397 } while (!a1.isStarted()); 398 399 // Time between pause and resume: totalDuration 400 long entireSpan = totalDuration * 2; 401 long frameDelta = l1.lastUpdateTime - l1.firstRunningFrameTime; 402 assertTrue(Math.abs(entireSpan - frameDelta) < TOLERANCE); 403 } 404 405 @SmallTest 406 public void testEnd() throws Throwable { 407 final MyListener l1 = new MyListener(); 408 final MyListener l2 = new MyListener(); 409 a1.addListener(l1); 410 a2.addListener(l2); 411 a1.addListener(new MyListener() { 412 @Override 413 public void onAnimationEnd(Animator anim) { 414 anim.cancel(); 415 } 416 }); 417 a2.addListener(new MyListener() { 418 @Override 419 public void onAnimationCancel(Animator anim) { 420 anim.end(); 421 } 422 }); 423 424 runTestOnUiThread(new Runnable() { 425 @Override 426 public void run() { 427 assertFalse(l1.cancelCalled); 428 assertFalse(l1.endCalled); 429 assertFalse(l2.cancelCalled); 430 assertFalse(l2.endCalled); 431 a1.start(); 432 a2.start(); 433 } 434 }); 435 Thread.sleep(POLL_INTERVAL); 436 runTestOnUiThread(new Runnable() { 437 @Override 438 public void run() { 439 a1.end(); 440 a2.cancel(); 441 } 442 }); 443 Thread.sleep(POLL_INTERVAL); 444 runTestOnUiThread(new Runnable() { 445 @Override 446 public void run() { 447 // Calling cancel from onAnimationEnd will be ignored. 448 assertFalse(l1.cancelCalled); 449 assertTrue(l1.endCalled); 450 assertTrue(l2.cancelCalled); 451 assertTrue(l2.endCalled); 452 453 float value1 = (Float) a1.getAnimatedValue(); 454 int value2 = (Integer) a2.getAnimatedValue(); 455 assertEquals(A1_END_VALUE, value1); 456 assertEquals(A2_END_VALUE, value2); 457 } 458 }); 459 460 } 461 462 @SmallTest 463 public void testEndValue() throws Throwable { 464 final MyListener l1 = new MyListener(); 465 a1.addListener(l1); 466 467 final MyListener l2 = new MyListener(); 468 a2.addListener(l2); 469 470 runTestOnUiThread(new Runnable() { 471 @Override 472 public void run() { 473 a1.start(); 474 a2.start(); 475 } 476 }); 477 478 Thread.sleep(POLL_INTERVAL); 479 runTestOnUiThread(new Runnable() { 480 @Override 481 public void run() { 482 // Animation has started but not finished, check animated values against end values 483 assertFalse(l1.endCalled); 484 assertFalse(l2.endCalled); 485 assertNotEqual(A1_END_VALUE, a1.getAnimatedValue()); 486 assertNotEqual(A1_END_VALUE, a2.getAnimatedValue()); 487 488 // Force a2 to end. 489 a2.end(); 490 } 491 }); 492 493 Thread.sleep(a1.getTotalDuration()); 494 495 runTestOnUiThread(new Runnable() { 496 @Override 497 public void run() { 498 assertFalse(l1.cancelCalled); 499 assertTrue(l1.endCalled); 500 assertFalse(l2.cancelCalled); 501 assertTrue(l2.endCalled); 502 503 // By now a1 should have finished normally and a2 has skipped to the end, check 504 // their end values. 505 assertEquals(A1_END_VALUE, ((Float) (a1.getAnimatedValue())).floatValue()); 506 assertEquals(A2_END_VALUE, ((Integer) (a2.getAnimatedValue())).intValue()); 507 } 508 }); 509 } 510 511 @SmallTest 512 public void testUpdateListener() throws InterruptedException { 513 514 final MyFrameCallbackProvider provider = new MyFrameCallbackProvider(); 515 long sleep = 0; 516 while (provider.mHandler == null) { 517 Thread.sleep(POLL_INTERVAL); 518 sleep += POLL_INTERVAL; 519 if (sleep > WAIT_TIME_OUT) { 520 break; 521 } 522 } 523 // Either the looper has started, or timed out 524 assertNotNull(provider.mHandler); 525 526 final MyListener listener = new MyListener(); 527 final MyUpdateListener l1 = new MyUpdateListener() { 528 @Override 529 public void onAnimationUpdate(ValueAnimator animation) { 530 long currentTime = SystemClock.uptimeMillis(); 531 long frameDelay = provider.getFrameDelay(); 532 if (lastUpdateTime > 0) { 533 // Error tolerance here is one frame. 534 assertTrue((currentTime - lastUpdateTime) < frameDelay * 2); 535 } else { 536 // First frame: 537 assertTrue(listener.startCalled); 538 assertTrue(listener.startTime > 0); 539 assertTrue(currentTime - listener.startTime < frameDelay * 2); 540 } 541 super.onAnimationUpdate(animation); 542 } 543 }; 544 a1.addUpdateListener(l1); 545 a1.addListener(listener); 546 a1.setStartDelay(100); 547 548 provider.mHandler.post(new Runnable() { 549 @Override 550 public void run() { 551 AnimationHandler.getInstance().setProvider(provider); 552 a1.start(); 553 } 554 }); 555 Thread.sleep(POLL_INTERVAL); 556 assertTrue(a1.isStarted()); 557 Thread.sleep(a1.getTotalDuration() + TOLERANCE); 558 // Finished by now. 559 assertFalse(a1.isStarted()); 560 assertTrue(listener.endTime > 0); 561 562 // Check the time difference between last frame and end time. 563 assertTrue(listener.endTime >= l1.lastUpdateTime); 564 assertTrue(listener.endTime - l1.lastUpdateTime < 2 * provider.getFrameDelay()); 565 } 566 567 568 @SmallTest 569 public void testConcurrentModification() throws Throwable { 570 // Attempt to modify list of animations as the list is being iterated 571 final ValueAnimator a0 = ValueAnimator.ofInt(100, 200).setDuration(500); 572 final ValueAnimator a3 = ValueAnimator.ofFloat(0, 1).setDuration(500); 573 final ValueAnimator a4 = ValueAnimator.ofInt(200, 300).setDuration(500); 574 final MyListener listener = new MyListener() { 575 @Override 576 public void onAnimationEnd(Animator anim) { 577 super.onAnimationEnd(anim); 578 // AnimationHandler should be iterating the list at the moment, end/cancel all 579 // the other animations. No ConcurrentModificationException should happen. 580 a0.cancel(); 581 a1.end(); 582 a3.end(); 583 a4.cancel(); 584 } 585 }; 586 a2.addListener(listener); 587 588 runTestOnUiThread(new Runnable() { 589 @Override 590 public void run() { 591 a0.start(); 592 a1.start(); 593 a2.start(); 594 a3.start(); 595 a4.start(); 596 } 597 }); 598 runTestOnUiThread(new Runnable() { 599 @Override 600 public void run() { 601 assertTrue(a0.isStarted()); 602 assertTrue(a1.isStarted()); 603 assertTrue(a2.isStarted()); 604 assertTrue(a3.isStarted()); 605 assertTrue(a4.isStarted()); 606 } 607 }); 608 Thread.sleep(POLL_INTERVAL); 609 runTestOnUiThread(new Runnable() { 610 @Override 611 public void run() { 612 // End the animator that should be in the middle of the list. 613 a2.end(); 614 } 615 }); 616 Thread.sleep(POLL_INTERVAL); 617 assertTrue(listener.endCalled); 618 assertFalse(a0.isStarted()); 619 assertFalse(a1.isStarted()); 620 assertFalse(a2.isStarted()); 621 assertFalse(a3.isStarted()); 622 assertFalse(a4.isStarted()); 623 } 624 625 @SmallTest 626 public void testSeek() throws Throwable { 627 final MyListener l1 = new MyListener(); 628 final MyListener l2 = new MyListener(); 629 final MyUpdateListener updateListener1 = new MyUpdateListener(); 630 final MyUpdateListener updateListener2 = new MyUpdateListener(); 631 final float a1StartFraction = 0.2f; 632 final float a2StartFraction = 0.3f; 633 634 // Extend duration so we have plenty of latitude to manipulate the animations when they 635 // are running. 636 a1.setDuration(1000); 637 a2.setDuration(1000); 638 a1.addListener(l1); 639 a2.addListener(l2); 640 a1.addUpdateListener(updateListener1); 641 a2.addUpdateListener(updateListener2); 642 TimeInterpolator interpolator = new LinearInterpolator(); 643 a1.setInterpolator(interpolator); 644 a2.setInterpolator(interpolator); 645 646 runTestOnUiThread(new Runnable() { 647 @Override 648 public void run() { 649 assertFalse(a1.isStarted()); 650 assertFalse(a1.isRunning()); 651 assertFalse(a2.isStarted()); 652 assertFalse(a2.isRunning()); 653 654 // Test isRunning() and isStarted() before and after seek 655 a1.setCurrentFraction(a1StartFraction); 656 a2.setCurrentFraction(a2StartFraction); 657 658 assertFalse(a1.isStarted()); 659 assertFalse(a1.isRunning()); 660 assertFalse(a2.isStarted()); 661 assertFalse(a2.isRunning()); 662 } 663 }); 664 Thread.sleep(POLL_INTERVAL); 665 666 // Start animation and seek during the animation. 667 runTestOnUiThread(new Runnable() { 668 @Override 669 public void run() { 670 assertFalse(a1.isStarted()); 671 assertFalse(a1.isRunning()); 672 assertFalse(a2.isStarted()); 673 assertFalse(a2.isRunning()); 674 assertEquals(a1StartFraction, a1.getAnimatedFraction()); 675 assertEquals(a2StartFraction, a2.getAnimatedFraction()); 676 677 a1.start(); 678 a2.start(); 679 } 680 }); 681 682 Thread.sleep(POLL_INTERVAL); 683 final float halfwayFraction = 0.5f; 684 runTestOnUiThread(new Runnable() { 685 @Override 686 public void run() { 687 assertTrue(l1.startCalled); 688 assertTrue(l2.startCalled); 689 assertFalse(l1.endCalled); 690 assertFalse(l2.endCalled); 691 692 // Check whether the animations start from the seeking fraction 693 assertTrue(updateListener1.startFraction >= a1StartFraction); 694 assertTrue(updateListener2.startFraction >= a2StartFraction); 695 696 assertTrue(a1.isStarted()); 697 assertTrue(a1.isRunning()); 698 assertTrue(a2.isStarted()); 699 assertTrue(a2.isRunning()); 700 701 a1.setCurrentFraction(halfwayFraction); 702 a2.setCurrentFraction(halfwayFraction); 703 } 704 }); 705 706 Thread.sleep(POLL_INTERVAL); 707 708 // Check that seeking during running doesn't change animation's internal state 709 runTestOnUiThread(new Runnable() { 710 @Override 711 public void run() { 712 assertTrue(l1.startCalled); 713 assertTrue(l2.startCalled); 714 assertFalse(l1.endCalled); 715 assertFalse(l2.endCalled); 716 717 assertTrue(a1.isStarted()); 718 assertTrue(a1.isRunning()); 719 assertTrue(a2.isStarted()); 720 assertTrue(a2.isRunning()); 721 } 722 }); 723 724 // Wait until the animators finish successfully. 725 long wait = Math.max(a1.getTotalDuration(), a2.getTotalDuration()); 726 Thread.sleep(wait); 727 728 runTestOnUiThread(new Runnable() { 729 @Override 730 public void run() { 731 // Verify that the animators have finished. 732 assertTrue(l1.endCalled); 733 assertTrue(l2.endCalled); 734 735 assertFalse(a1.isStarted()); 736 assertFalse(a2.isStarted()); 737 assertFalse(a1.isRunning()); 738 assertFalse(a2.isRunning()); 739 } 740 }); 741 742 // Re-start animator a1 after it ends normally, and check that seek value from last run 743 // does not affect the new run. 744 updateListener1.reset(); 745 runTestOnUiThread(new Runnable() { 746 @Override 747 public void run() { 748 a1.start(); 749 } 750 }); 751 752 Thread.sleep(POLL_INTERVAL); 753 runTestOnUiThread(new Runnable() { 754 @Override 755 public void run() { 756 assertTrue(updateListener1.wasRunning); 757 assertTrue(updateListener1.startFraction >= 0); 758 assertTrue(updateListener1.startFraction < halfwayFraction); 759 a1.end(); 760 } 761 }); 762 763 } 764 765 @SmallTest 766 public void testSeekWhileRunning() throws Throwable { 767 // Seek one animator to the beginning and the other one to the end when they are running. 768 final MyListener l1 = new MyListener(); 769 final MyListener l2 = new MyListener(); 770 a1.addListener(l1); 771 a2.addListener(l2); 772 runTestOnUiThread(new Runnable() { 773 @Override 774 public void run() { 775 assertFalse(l1.startCalled); 776 assertFalse(l2.startCalled); 777 assertEquals(0f, a1.getAnimatedFraction()); 778 assertEquals(0f, a2.getAnimatedFraction()); 779 a1.start(); 780 a2.start(); 781 } 782 }); 783 Thread.sleep(POLL_INTERVAL); 784 runTestOnUiThread(new Runnable() { 785 @Override 786 public void run() { 787 assertFalse(l1.endCalled); 788 assertFalse(l2.endCalled); 789 assertTrue(a1.isRunning()); 790 assertTrue(a2.isRunning()); 791 // During the run, seek one to the beginning, the other to the end 792 a1.setCurrentFraction(0f); 793 a2.setCurrentFraction(1f); 794 } 795 }); 796 Thread.sleep(POLL_INTERVAL); 797 runTestOnUiThread(new Runnable() { 798 @Override 799 public void run() { 800 // Check that a2 has finished due to the seeking, but a1 hasn't finished. 801 assertFalse(l1.endCalled); 802 assertTrue(l2.endCalled); 803 assertEquals(1f, a2.getAnimatedFraction()); 804 } 805 }); 806 807 Thread.sleep(a1.getTotalDuration()); 808 runTestOnUiThread(new Runnable() { 809 @Override 810 public void run() { 811 // By now a1 should finish also. 812 assertTrue(l1.endCalled); 813 assertEquals(1f, a1.getAnimatedFraction()); 814 } 815 }); 816 } 817 818 @SmallTest 819 public void testEndBeforeStart() throws Throwable { 820 // This test calls two animators that are not yet started. One animator has completed a 821 // previous run but hasn't started since then, the other one has never run. When end() is 822 // called on these two animators, we expected their animation listeners to receive both 823 // onAnimationStarted(Animator) and onAnimationEnded(Animator) callbacks, in that sequence. 824 825 a1.setStartDelay(20); 826 827 // First start a1's first run. 828 final MyListener normalEndingListener = new MyListener(); 829 a1.addListener(normalEndingListener); 830 runTestOnUiThread(new Runnable() { 831 @Override 832 public void run() { 833 assertFalse(a1.isStarted()); 834 assertFalse(normalEndingListener.startCalled); 835 assertFalse(normalEndingListener.endCalled); 836 // Start normally 837 a1.start(); 838 } 839 }); 840 841 Thread.sleep(a1.getTotalDuration() + POLL_INTERVAL); 842 843 // a1 should have finished by now. 844 runTestOnUiThread(new Runnable() { 845 @Override 846 public void run() { 847 // Call end() on both a1 and a2 without calling start() 848 final MyListener l1 = new MyListener(); 849 a1.addListener(l1); 850 final MyListener l2 = new MyListener(); 851 a2.addListener(l2); 852 853 assertFalse(a1.isStarted()); 854 assertFalse(l1.startCalled); 855 assertFalse(l1.endCalled); 856 assertFalse(a2.isStarted()); 857 assertFalse(l2.startCalled); 858 assertFalse(l1.endCalled); 859 860 a1.end(); 861 a2.end(); 862 863 // Check that both animators' listeners have received the animation callbacks. 864 assertTrue(l1.startCalled); 865 assertTrue(l1.endCalled); 866 assertFalse(a1.isStarted()); 867 assertTrue(l1.endTime >= l1.startTime); 868 869 assertTrue(l2.startCalled); 870 assertTrue(l2.endCalled); 871 assertFalse(a2.isStarted()); 872 assertTrue(l2.endTime >= l1.startTime); 873 } 874 }); 875 } 876 877 @SmallTest 878 public void testZeroDuration() throws Throwable { 879 // Run two animators with zero duration, with one running forward and the other one 880 // backward. Check that the animations start and finish with the correct end fractions. 881 a1.setDuration(0); 882 a2.setDuration(0); 883 884 // Set a fraction on an animation with 0-duration 885 final ValueAnimator a3 = ValueAnimator.ofInt(0, 100); 886 a3.setDuration(0); 887 a3.setCurrentFraction(1.0f); 888 assertEquals(1.0f, a3.getAnimatedFraction()); 889 890 final MyListener l1 = new MyListener(); 891 final MyListener l2 = new MyListener(); 892 final MyListener l3 = new MyListener(); 893 a1.addListener(l1); 894 a2.addListener(l2); 895 a3.addListener(l3); 896 runTestOnUiThread(new Runnable() { 897 @Override 898 public void run() { 899 assertFalse(l1.startCalled); 900 assertFalse(l2.startCalled); 901 assertFalse(l3.startCalled); 902 assertFalse(l1.endCalled); 903 assertFalse(l2.endCalled); 904 assertFalse(l3.endCalled); 905 a1.start(); 906 a2.reverse(); 907 a3.start(); 908 // Check that the animators' values are immediately set to end value in the case of 909 // 0-duration. 910 assertEquals(A1_END_VALUE, a1.getAnimatedValue()); 911 assertEquals(A2_START_VALUE, a2.getAnimatedValue()); 912 } 913 }); 914 Thread.sleep(POLL_INTERVAL); 915 runTestOnUiThread(new Runnable() { 916 @Override 917 public void run() { 918 // Check that the animators have started and finished with the right values. 919 assertTrue(l1.startCalled); 920 assertTrue(l2.startCalled); 921 assertTrue(l3.startCalled); 922 assertTrue(l1.endCalled); 923 assertTrue(l2.endCalled); 924 assertTrue(l3.endCalled); 925 assertEquals(1.0f, a1.getAnimatedFraction()); 926 assertEquals(0f, a2.getAnimatedFraction()); 927 assertEquals(1f, a3.getAnimatedFraction()); 928 assertEquals(A1_END_VALUE, a1.getAnimatedValue()); 929 assertEquals(A2_START_VALUE, a2.getAnimatedValue()); 930 assertEquals(100, a3.getAnimatedValue()); 931 } 932 }); 933 } 934 935 @SmallTest 936 public void testZeroScale() throws Throwable { 937 // Test whether animations would end properly when the scale is forced to be zero 938 float scale = ValueAnimator.getDurationScale(); 939 ValueAnimator.setDurationScale(0f); 940 941 // Run two animators, one of which has a start delay, after setting the duration scale to 0 942 a1.setStartDelay(200); 943 final MyListener l1 = new MyListener(); 944 final MyListener l2 = new MyListener(); 945 a1.addListener(l1); 946 a2.addListener(l2); 947 948 runTestOnUiThread(new Runnable() { 949 @Override 950 public void run() { 951 assertFalse(l1.startCalled); 952 assertFalse(l2.startCalled); 953 assertFalse(l1.endCalled); 954 assertFalse(l2.endCalled); 955 956 a1.start(); 957 a2.start(); 958 959 // In the case of 0 duration scale applied to a non-0 duration, check that the 960 // value is immediately set to the start value. 961 assertEquals(A2_START_VALUE, a2.getAnimatedValue()); 962 } 963 }); 964 Thread.sleep(POLL_INTERVAL); 965 966 runTestOnUiThread(new Runnable() { 967 @Override 968 public void run() { 969 assertTrue(l1.startCalled); 970 assertTrue(l2.startCalled); 971 assertTrue(l1.endCalled); 972 assertTrue(l2.endCalled); 973 assertEquals(A1_END_VALUE, a1.getAnimatedValue()); 974 assertEquals(A2_END_VALUE, a2.getAnimatedValue()); 975 } 976 }); 977 978 // Restore duration scale 979 ValueAnimator.setDurationScale(scale); 980 } 981 982 @SmallTest 983 public void testReverse() throws Throwable { 984 // Prolong animators duration so that we can do multiple checks during their run 985 final ValueAnimator a3 = ValueAnimator.ofInt(0, 100); 986 a1.setDuration(400); 987 a2.setDuration(600); 988 a3.setDuration(400); 989 final MyListener l1 = new MyListener(); 990 final MyListener l2 = new MyListener(); 991 final MyListener l3 = new MyListener(); 992 a1.addListener(l1); 993 a2.addListener(l2); 994 a3.addListener(l3); 995 996 // Reverse three animators, seek one to the beginning and another to the end, and force 997 // to end the third one during reversing. 998 runTestOnUiThread(new Runnable() { 999 @Override 1000 public void run() { 1001 assertFalse(l1.startCalled); 1002 assertFalse(l2.startCalled); 1003 assertFalse(l3.startCalled); 1004 assertFalse(l1.endCalled); 1005 assertFalse(l2.endCalled); 1006 assertFalse(l3.endCalled); 1007 a1.reverse(); 1008 a2.reverse(); 1009 a3.reverse(); 1010 } 1011 }); 1012 Thread.sleep(POLL_INTERVAL); 1013 runTestOnUiThread(new Runnable() { 1014 @Override 1015 public void run() { 1016 assertTrue(l1.startCalled); 1017 assertTrue(l2.startCalled); 1018 assertTrue(l3.startCalled); 1019 1020 a1.setCurrentFraction(0f); 1021 a2.setCurrentFraction(1f); 1022 a3.end(); 1023 1024 // Check that the fraction has been set, and the getter returns the correct values. 1025 assertEquals(1f, a1.getAnimatedFraction()); 1026 assertEquals(0f, a2.getAnimatedFraction()); 1027 } 1028 }); 1029 Thread.sleep(POLL_INTERVAL); 1030 1031 // By now, a2 should have finished due to the seeking. It wouldn't have finished otherwise. 1032 runTestOnUiThread(new Runnable() { 1033 @Override 1034 public void run() { 1035 // Check that both animations have started, and a2 has finished. 1036 assertFalse(l1.endCalled); 1037 assertTrue(l2.endCalled); 1038 assertTrue(l3.endCalled); 1039 } 1040 }); 1041 Thread.sleep(a1.getTotalDuration()); 1042 1043 runTestOnUiThread(new Runnable() { 1044 @Override 1045 public void run() { 1046 // Verify that a1 has finished as well. 1047 assertTrue(l1.endCalled); 1048 assertEquals(0f, a1.getAnimatedFraction()); 1049 assertEquals(0f, a2.getAnimatedFraction()); 1050 assertEquals(0f, a3.getAnimatedFraction()); 1051 } 1052 }); 1053 } 1054 1055 class MyUpdateListener implements ValueAnimator.AnimatorUpdateListener { 1056 boolean wasRunning = false; 1057 long firstRunningFrameTime = -1; 1058 long lastUpdateTime = -1; 1059 float startFraction = 0; 1060 1061 @Override 1062 public void onAnimationUpdate(ValueAnimator animation) { 1063 lastUpdateTime = SystemClock.uptimeMillis(); 1064 if (animation.isRunning() && !wasRunning) { 1065 // Delay has passed 1066 firstRunningFrameTime = lastUpdateTime; 1067 startFraction = animation.getAnimatedFraction(); 1068 wasRunning = animation.isRunning(); 1069 } 1070 } 1071 1072 void reset() { 1073 wasRunning = false; 1074 firstRunningFrameTime = -1; 1075 lastUpdateTime = -1; 1076 startFraction = 0; 1077 } 1078 } 1079 1080 class MyListener implements Animator.AnimatorListener { 1081 boolean startCalled = false; 1082 boolean cancelCalled = false; 1083 boolean endCalled = false; 1084 long startTime = -1; 1085 long endTime = -1; 1086 1087 @Override 1088 public void onAnimationStart(Animator animation) { 1089 startCalled = true; 1090 startTime = SystemClock.uptimeMillis(); 1091 } 1092 1093 @Override 1094 public void onAnimationEnd(Animator animation) { 1095 endCalled = true; 1096 endTime = SystemClock.uptimeMillis(); 1097 } 1098 1099 @Override 1100 public void onAnimationCancel(Animator animation) { 1101 cancelCalled = true; 1102 } 1103 1104 @Override 1105 public void onAnimationRepeat(Animator animation) { 1106 1107 } 1108 } 1109 1110 class MyPauseListener implements Animator.AnimatorPauseListener { 1111 boolean pauseCalled = false; 1112 boolean resumeCalled = false; 1113 1114 @Override 1115 public void onAnimationPause(Animator animation) { 1116 pauseCalled = true; 1117 } 1118 1119 @Override 1120 public void onAnimationResume(Animator animation) { 1121 resumeCalled = true; 1122 } 1123 } 1124 1125 class MyFrameCallbackProvider implements AnimationHandler.AnimationFrameCallbackProvider { 1126 1127 Handler mHandler = null; 1128 private final static int MSG_FRAME = 0; 1129 private long mFrameDelay = DEFAULT_FRAME_INTERVAL; 1130 private ArrayList<Choreographer.FrameCallback> mFrameCallbacks = new ArrayList<>(); 1131 1132 final LooperThread mThread = new LooperThread(); 1133 1134 public MyFrameCallbackProvider() { 1135 mThread.start(); 1136 } 1137 1138 @Override 1139 public void postFrameCallback(Choreographer.FrameCallback callback) { 1140 mHandler.sendEmptyMessageDelayed(MSG_FRAME, mFrameDelay); 1141 if (!mFrameCallbacks.contains(callback)) { 1142 mFrameCallbacks.add(callback); 1143 } 1144 } 1145 1146 @Override 1147 public void postCommitCallback(Runnable runnable) { 1148 // Run the runnable after a commit delay 1149 mHandler.postDelayed(runnable, COMMIT_DELAY); 1150 } 1151 1152 @Override 1153 public long getFrameTime() { 1154 return SystemClock.uptimeMillis(); 1155 } 1156 1157 @Override 1158 public long getFrameDelay() { 1159 return mFrameDelay; 1160 } 1161 1162 @Override 1163 public void setFrameDelay(long delay) { 1164 mFrameDelay = delay; 1165 if (mFrameCallbacks.size() != 0) { 1166 mHandler.removeMessages(MSG_FRAME); 1167 mHandler.sendEmptyMessageDelayed(MSG_FRAME, mFrameDelay); 1168 } 1169 } 1170 1171 class LooperThread extends Thread { 1172 public void run() { 1173 Looper.prepare(); 1174 mHandler = new Handler() { 1175 public void handleMessage(Message msg) { 1176 // Handle message here. 1177 switch (msg.what) { 1178 case MSG_FRAME: 1179 for (int i = 0; i < mFrameCallbacks.size(); i++) { 1180 mFrameCallbacks.get(i).doFrame(SystemClock.uptimeMillis()); 1181 } 1182 break; 1183 default: 1184 break; 1185 } 1186 } 1187 }; 1188 Looper.loop(); 1189 } 1190 } 1191 } 1192} 1193