1 /* 2 * Copyright 2018 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 17 package androidx.core.animation; 18 19 import static androidx.core.animation.AnimatorSetTest.AnimEvent.EventType.END; 20 import static androidx.core.animation.AnimatorSetTest.AnimEvent.EventType.START; 21 22 import static org.junit.Assert.assertEquals; 23 import static org.junit.Assert.assertFalse; 24 import static org.junit.Assert.assertSame; 25 import static org.junit.Assert.assertTrue; 26 27 import android.util.Property; 28 29 import androidx.test.annotation.UiThreadTest; 30 import androidx.test.ext.junit.runners.AndroidJUnit4; 31 import androidx.test.filters.SmallTest; 32 33 import org.jspecify.annotations.NonNull; 34 import org.junit.After; 35 import org.junit.Before; 36 import org.junit.ClassRule; 37 import org.junit.Test; 38 import org.junit.runner.RunWith; 39 40 import java.util.ArrayList; 41 import java.util.List; 42 import java.util.concurrent.atomic.AtomicLong; 43 44 @SmallTest 45 @RunWith(AndroidJUnit4.class) 46 public class AnimatorSetTest { 47 private AnimatorSet mAnimatorSet; 48 private float mPreviousDurationScale = 1.0f; 49 private ValueAnimator mAnim1; 50 private ValueAnimator mAnim2; 51 private static final float EPSILON = 0.001f; 52 enum PlayOrder { 53 SEQUENTIAL, 54 TOGETHER 55 } 56 57 @Before setup()58 public void setup() { 59 mPreviousDurationScale = ValueAnimator.getDurationScale(); 60 ValueAnimator.setDurationScale(1.0f); 61 mAnim1 = ValueAnimator.ofFloat(0f, 100f); 62 mAnim2 = ValueAnimator.ofInt(100, 200); 63 } 64 65 @After tearDown()66 public void tearDown() { 67 ValueAnimator.setDurationScale(mPreviousDurationScale); 68 } 69 70 @ClassRule 71 public static AnimatorTestRule sAnimatorTestRule = new AnimatorTestRule(); 72 73 @UiThreadTest 74 @Test testPlaySequentially()75 public void testPlaySequentially() { 76 77 List<Animator> animators = new ArrayList<Animator>(); 78 animators.add(mAnim1); 79 animators.add(mAnim2); 80 mAnimatorSet = new AnimatorSet(); 81 mAnimatorSet.playSequentially(animators); 82 verifyPlayOrder(mAnimatorSet, new Animator[] {mAnim1, mAnim2}, PlayOrder.SEQUENTIAL); 83 84 AnimatorSet set = new AnimatorSet(); 85 set.playSequentially(mAnim1, mAnim2); 86 verifyPlayOrder(set, new Animator[] {mAnim1, mAnim2}, PlayOrder.SEQUENTIAL); 87 } 88 89 @UiThreadTest 90 @Test testPlayTogether()91 public void testPlayTogether() { 92 93 List<Animator> animators = new ArrayList<Animator>(); 94 animators.add(mAnim1); 95 animators.add(mAnim2); 96 mAnimatorSet = new AnimatorSet(); 97 mAnimatorSet.playTogether(animators); 98 verifyPlayOrder(mAnimatorSet, new Animator[] {mAnim1, mAnim2}, PlayOrder.TOGETHER); 99 100 AnimatorSet set = new AnimatorSet(); 101 set.playTogether(mAnim1, mAnim2); 102 verifyPlayOrder(set, new Animator[] {mAnim1, mAnim2}, PlayOrder.TOGETHER); 103 } 104 105 /** 106 * Start the animator, and verify the animators are played sequentially in the order that is 107 * defined in the array. 108 * 109 * @param set AnimatorSet to be started and verified 110 * @param animators animators that we put in the AnimatorSet, in the order that they'll play 111 */ verifyPlayOrder(final AnimatorSet set, Animator[] animators, PlayOrder playOrder)112 private void verifyPlayOrder(final AnimatorSet set, Animator[] animators, PlayOrder playOrder) { 113 ArrayList<AnimEvent> animEvents = registerAnimatorsForEvents(animators); 114 115 set.start(); 116 117 sAnimatorTestRule.advanceTimeBy(set.getStartDelay()); 118 for (int i = 0; i < animators.length; i++) { 119 sAnimatorTestRule.advanceTimeBy(animators[i].getTotalDuration()); 120 } 121 122 // All animations should finish by now 123 int animatorNum = animators.length; 124 assertEquals(animatorNum * 2, animEvents.size()); 125 126 if (playOrder == PlayOrder.SEQUENTIAL) { 127 for (int i = 0; i < animatorNum; i++) { 128 assertEquals(START, animEvents.get(i * 2).mType); 129 assertEquals(animators[i], animEvents.get(i * 2).mAnim); 130 assertEquals(END, animEvents.get(i * 2 + 1).mType); 131 assertEquals(animators[i], animEvents.get(i * 2 + 1).mAnim); 132 } 133 } else { 134 for (int i = 0; i < animatorNum; i++) { 135 assertEquals(START, animEvents.get(i).mType); 136 assertEquals(animators[i], animEvents.get(i).mAnim); 137 } 138 } 139 } 140 registerAnimatorsForEvents(Animator[] animators)141 private ArrayList<AnimEvent> registerAnimatorsForEvents(Animator[] animators) { 142 final ArrayList<AnimEvent> animEvents = new ArrayList<>(); 143 Animator.AnimatorListener listener = new Animator.AnimatorListener() { 144 @Override 145 public void onAnimationStart(@NonNull Animator animation) { 146 animEvents.add(new AnimEvent(START, animation)); 147 } 148 149 @Override 150 public void onAnimationEnd(@NonNull Animator animation) { 151 animEvents.add(new AnimEvent(END, animation)); 152 } 153 154 @Override 155 public void onAnimationCancel(@NonNull Animator animation) { 156 157 } 158 159 @Override 160 public void onAnimationRepeat(@NonNull Animator animation) { 161 162 } 163 }; 164 165 for (int i = 0; i < animators.length; i++) { 166 animators[i].removeListener(listener); 167 animators[i].addListener(listener); 168 } 169 return animEvents; 170 } 171 172 @UiThreadTest 173 @Test testPlayBeforeAfter()174 public void testPlayBeforeAfter() { 175 176 final ValueAnimator anim3 = ValueAnimator.ofFloat(200f, 300f); 177 178 AnimatorSet set = new AnimatorSet(); 179 set.play(mAnim1).before(mAnim2).after(anim3); 180 181 verifyPlayOrder(set, new Animator[] {anim3, mAnim1, mAnim2}, PlayOrder.SEQUENTIAL); 182 } 183 184 @UiThreadTest 185 @Test testListenerCallbackOnEmptySet()186 public void testListenerCallbackOnEmptySet() { 187 // Create an AnimatorSet that only contains one empty AnimatorSet, and checks the callback 188 // sequence by checking the time stamps of the callbacks. 189 final AnimatorSet emptySet = new AnimatorSet(); 190 final AnimatorSet set = new AnimatorSet(); 191 set.play(emptySet); 192 193 194 ArrayList<AnimEvent> animEvents = registerAnimatorsForEvents( 195 new Animator[] {emptySet, set}); 196 set.start(); 197 sAnimatorTestRule.advanceTimeBy(10); 198 199 // Check callback sequence via Animator Events 200 assertEquals(animEvents.get(0).mAnim, set); 201 assertEquals(animEvents.get(0).mType, START); 202 assertEquals(animEvents.get(1).mAnim, emptySet); 203 assertEquals(animEvents.get(1).mType, START); 204 205 assertEquals(animEvents.get(2).mAnim, emptySet); 206 assertEquals(animEvents.get(2).mType, END); 207 assertEquals(animEvents.get(3).mAnim, set); 208 assertEquals(animEvents.get(3).mType, END); 209 } 210 211 @UiThreadTest 212 @Test testPause()213 public void testPause() { 214 final ValueAnimator anim = ValueAnimator.ofFloat(0f, 1000f); 215 anim.setDuration(1000L); 216 anim.setInterpolator(new LinearInterpolator()); 217 final AnimatorSet set = new AnimatorSet(); 218 set.playTogether(anim); 219 220 set.start(); 221 sAnimatorTestRule.advanceTimeBy(300); 222 assertEquals(300L, set.getCurrentPlayTime()); 223 assertEquals(300f, (float) anim.getAnimatedValue(), EPSILON); 224 225 set.pause(); 226 sAnimatorTestRule.advanceTimeBy(300); 227 assertEquals(300L, set.getCurrentPlayTime()); 228 assertEquals(300f, (float) anim.getAnimatedValue(), EPSILON); 229 230 set.resume(); 231 sAnimatorTestRule.advanceTimeBy(300); 232 assertEquals(600L, set.getCurrentPlayTime()); 233 assertEquals(600f, (float) anim.getAnimatedValue(), EPSILON); 234 } 235 236 @UiThreadTest 237 @Test testPauseAndResume()238 public void testPauseAndResume() { 239 final AnimatorSet set = new AnimatorSet(); 240 set.playTogether(mAnim1, mAnim2); 241 242 set.start(); 243 sAnimatorTestRule.advanceTimeBy(0); 244 set.pause(); 245 assertTrue(set.isPaused()); 246 sAnimatorTestRule.advanceTimeBy(5); 247 248 // After 10s, set is still not yet finished. 249 sAnimatorTestRule.advanceTimeBy(10000); 250 assertTrue(set.isStarted()); 251 assertTrue(set.isPaused()); 252 set.resume(); 253 254 sAnimatorTestRule.advanceTimeBy(5); 255 assertTrue(set.isStarted()); 256 assertFalse(set.isPaused()); 257 258 sAnimatorTestRule.advanceTimeBy(10000); 259 assertFalse(set.isStarted()); 260 assertFalse(set.isPaused()); 261 } 262 263 @UiThreadTest 264 @Test testPauseBeforeStart()265 public void testPauseBeforeStart() { 266 final AnimatorSet set = new AnimatorSet(); 267 set.playSequentially(mAnim1, mAnim2); 268 269 set.pause(); 270 // Verify that pause should have no effect on a not-yet-started animator. 271 assertFalse(set.isPaused()); 272 set.start(); 273 sAnimatorTestRule.advanceTimeBy(0); 274 assertTrue(set.isStarted()); 275 276 sAnimatorTestRule.advanceTimeBy(set.getTotalDuration()); 277 assertFalse(set.isStarted()); 278 } 279 280 @UiThreadTest 281 @Test testPauseRewindResume()282 public void testPauseRewindResume() { 283 final AnimatorSet set = new AnimatorSet(); 284 final ValueAnimator a1 = ValueAnimator.ofFloat(0f, 1000f); 285 a1.setDuration(1000); 286 final ValueAnimator a2 = ValueAnimator.ofInt(0, 1000); 287 a2.setDuration(1000); 288 set.playSequentially(a1, a2); 289 set.setInterpolator(new LinearInterpolator()); 290 291 assertEquals(2000L, set.getTotalDuration()); 292 set.start(); 293 sAnimatorTestRule.advanceTimeBy(1500L); 294 assertEquals(1000f, (float) a1.getAnimatedValue(), EPSILON); 295 assertEquals(500, (int) a2.getAnimatedValue()); 296 297 set.pause(); 298 set.setCurrentPlayTime(500L); 299 assertEquals(500f, (float) a1.getAnimatedValue(), EPSILON); 300 assertEquals(0, (int) a2.getAnimatedValue()); 301 302 set.resume(); 303 sAnimatorTestRule.advanceTimeBy(250L); 304 assertEquals(750f, (float) a1.getAnimatedValue(), EPSILON); 305 assertEquals(0, (int) a2.getAnimatedValue()); 306 307 sAnimatorTestRule.advanceTimeBy(750L); 308 assertEquals(1000f, (float) a1.getAnimatedValue(), EPSILON); 309 assertEquals(500, (int) a2.getAnimatedValue()); 310 } 311 312 @UiThreadTest 313 @Test testSeekAfterPause()314 public void testSeekAfterPause() { 315 final AnimatorSet set = new AnimatorSet(); 316 ValueAnimator a1 = ValueAnimator.ofFloat(0f, 50f); 317 a1.setDuration(50); 318 ValueAnimator a2 = ValueAnimator.ofFloat(50, 100f); 319 a2.setDuration(50); 320 set.playSequentially(a1, a2); 321 set.setInterpolator(new LinearInterpolator()); 322 323 set.start(); 324 set.pause(); 325 set.setCurrentPlayTime(60); 326 assertEquals((long) set.getCurrentPlayTime(), 60); 327 assertEquals((float) a1.getAnimatedValue(), 50f, EPSILON); 328 assertEquals((float) a2.getAnimatedValue(), 60f, EPSILON); 329 330 set.setCurrentPlayTime(40); 331 assertEquals((long) set.getCurrentPlayTime(), 40); 332 assertEquals((float) a1.getAnimatedValue(), 40f, EPSILON); 333 assertEquals((float) a2.getAnimatedValue(), 50f, EPSILON); 334 335 set.cancel(); 336 } 337 338 @UiThreadTest 339 @Test testSeekListener()340 public void testSeekListener() { 341 final AnimatorSet animatorSet = new AnimatorSet(); 342 ValueAnimator anim = ValueAnimator.ofFloat(0f, 1000f); 343 anim.setDuration(1000); 344 animatorSet.playTogether(anim); 345 final AtomicLong notifiedPlayTime = new AtomicLong(0L); 346 animatorSet.addUpdateListener((animation) -> { 347 final AnimatorSet set = (AnimatorSet) animation; 348 notifiedPlayTime.set(set.getCurrentPlayTime()); 349 }); 350 animatorSet.setCurrentPlayTime(0L); 351 assertEquals(0L, notifiedPlayTime.get()); 352 animatorSet.setCurrentPlayTime(100L); 353 assertEquals(100L, notifiedPlayTime.get()); 354 } 355 356 @UiThreadTest 357 @Test testDuration()358 public void testDuration() { 359 mAnim1.setRepeatCount(ValueAnimator.INFINITE); 360 Animator[] animatorArray = {mAnim1, mAnim2}; 361 362 mAnimatorSet = new AnimatorSet(); 363 mAnimatorSet.playTogether(animatorArray); 364 mAnimatorSet.setDuration(1000); 365 366 assertEquals(mAnimatorSet.getDuration(), 1000); 367 } 368 369 @UiThreadTest 370 @Test testStartDelay()371 public void testStartDelay() { 372 mAnim1.setRepeatCount(ValueAnimator.INFINITE); 373 Animator[] animatorArray = {mAnim1, mAnim2}; 374 375 mAnimatorSet = new AnimatorSet(); 376 mAnimatorSet.playTogether(animatorArray); 377 mAnimatorSet.setStartDelay(10); 378 379 assertEquals(mAnimatorSet.getStartDelay(), 10); 380 } 381 382 /** 383 * This test sets up an AnimatorSet with start delay. One of the child animators also has 384 * start delay. We then verify that start delay was handled correctly on both AnimatorSet 385 * and individual animator level. 386 */ 387 @UiThreadTest 388 @Test testReverseWithStartDelay()389 public void testReverseWithStartDelay() { 390 ValueAnimator a1 = ValueAnimator.ofFloat(0f, 1f); 391 a1.setDuration(200); 392 393 ValueAnimator a2 = ValueAnimator.ofFloat(1f, 2f); 394 a2.setDuration(200); 395 // Set start delay on a2 so that the delay is passed 100ms after a1 is finished. 396 a2.setStartDelay(300); 397 398 AnimatorSet set = new AnimatorSet(); 399 set.playTogether(a1, a2); 400 set.setStartDelay(1000); 401 402 set.reverse(); 403 sAnimatorTestRule.advanceTimeBy(0); 404 assertTrue(a2.isStarted()); 405 assertTrue(a2.isRunning()); 406 assertFalse(a1.isStarted()); 407 408 // a2 should finish 200ms after reverse started 409 sAnimatorTestRule.advanceTimeBy(200); 410 assertFalse(a2.isStarted()); 411 // By the time a2 finishes reversing, a1 should not have started. 412 assertFalse(a1.isStarted()); 413 414 sAnimatorTestRule.advanceTimeBy(100); 415 assertTrue(a1.isStarted()); 416 417 // a1 finishes within 200ms after starting 418 sAnimatorTestRule.advanceTimeBy(200); 419 assertFalse(a1.isStarted()); 420 assertFalse(set.isStarted()); 421 422 set.cancel(); 423 } 424 425 /** 426 * Test that duration scale is handled correctly in the AnimatorSet. 427 */ 428 @UiThreadTest 429 @Test testZeroDurationScale()430 public void testZeroDurationScale() { 431 ValueAnimator.setDurationScale(0); 432 433 AnimatorSet set = new AnimatorSet(); 434 set.playSequentially(mAnim1, mAnim2); 435 set.setStartDelay(1000); 436 437 set.start(); 438 assertFalse(set.isStarted()); 439 } 440 441 /** 442 * Test that non-zero duration scale is handled correctly in the AnimatorSet. 443 */ 444 @UiThreadTest 445 @Test testDurationScale()446 public void testDurationScale() { 447 // Change the duration scale to 3 448 ValueAnimator.setDurationScale(3f); 449 450 ValueAnimator a1 = ValueAnimator.ofFloat(0f, 1f); 451 a1.setDuration(100); 452 453 ValueAnimator a2 = ValueAnimator.ofFloat(1f, 2f); 454 a2.setDuration(100); 455 // Set start delay on a2 so that the delay is passed 100ms after a1 is finished. 456 a2.setStartDelay(200); 457 458 AnimatorSet set = new AnimatorSet(); 459 set.playSequentially(a1, a2); 460 set.setStartDelay(200); 461 462 // Sleep for part of the start delay and check that no child animator has started, to verify 463 // that the duration scale has been properly scaled. 464 set.start(); 465 sAnimatorTestRule.advanceTimeBy(0); 466 assertFalse(set.isRunning()); 467 // start delay of the set should be scaled to 600ms 468 sAnimatorTestRule.advanceTimeBy(550); 469 assertFalse(set.isRunning()); 470 471 sAnimatorTestRule.advanceTimeBy(50); 472 assertTrue(set.isRunning()); 473 assertTrue(a1.isStarted()); 474 assertFalse(a2.isStarted()); 475 476 // Verify that a1 finish in 300ms (3x its defined duration) 477 sAnimatorTestRule.advanceTimeBy(300); 478 assertFalse(a1.isStarted()); 479 assertTrue(a2.isStarted()); 480 assertFalse(a2.isRunning()); 481 482 // a2 should finish the delay stage now 483 sAnimatorTestRule.advanceTimeBy(600); 484 assertTrue(a2.isStarted()); 485 assertTrue(a2.isRunning()); 486 487 sAnimatorTestRule.advanceTimeBy(300); 488 assertFalse(a2.isStarted()); 489 assertFalse(a2.isRunning()); 490 assertFalse(set.isStarted()); 491 } 492 493 @UiThreadTest 494 @Test testClone()495 public void testClone() { 496 final AnimatorSet set1 = new AnimatorSet(); 497 final AnimatorListenerAdapter setListener = new AnimatorListenerAdapter() {}; 498 set1.addListener(setListener); 499 500 ObjectAnimator animator1 = new ObjectAnimator(); 501 animator1.setDuration(100); 502 animator1.setPropertyName("x"); 503 animator1.setIntValues(5); 504 animator1.setInterpolator(new LinearInterpolator()); 505 AnimatorListenerAdapter listener1 = new AnimatorListenerAdapter(){}; 506 AnimatorListenerAdapter listener2 = new AnimatorListenerAdapter(){}; 507 animator1.addListener(listener1); 508 509 ObjectAnimator animator2 = new ObjectAnimator(); 510 animator2.setDuration(100); 511 animator2.setInterpolator(new LinearInterpolator()); 512 animator2.addListener(listener2); 513 animator2.setPropertyName("y"); 514 animator2.setIntValues(10); 515 516 set1.playTogether(animator1, animator2); 517 518 class AnimateObject { 519 public int x = 1; 520 public int y = 2; 521 public void setX(int val) { 522 x = val; 523 } 524 525 public void setY(int val) { 526 y = val; 527 } 528 } 529 set1.setTarget(new AnimateObject()); 530 531 set1.start(); 532 assertTrue(set1.isStarted()); 533 534 animator1.getListeners(); 535 AnimatorSet set2 = set1.clone(); 536 assertFalse(set2.isStarted()); 537 538 assertEquals(2, set2.getChildAnimations().size()); 539 540 Animator clone1 = set2.getChildAnimations().get(0); 541 Animator clone2 = set2.getChildAnimations().get(1); 542 543 assertTrue(clone1.getListeners().contains(listener1)); 544 assertTrue(clone2.getListeners().contains(listener2)); 545 546 assertTrue(set2.getListeners().contains(setListener)); 547 548 for (Animator.AnimatorListener listener : set1.getListeners()) { 549 assertTrue(set2.getListeners().contains(listener)); 550 } 551 552 assertEquals(animator1.getDuration(), clone1.getDuration()); 553 assertEquals(animator2.getDuration(), clone2.getDuration()); 554 assertSame(animator1.getInterpolator(), clone1.getInterpolator()); 555 assertSame(animator2.getInterpolator(), clone2.getInterpolator()); 556 set1.cancel(); 557 } 558 559 /** 560 * Testing seeking in an AnimatorSet containing sequential animators. 561 */ 562 @UiThreadTest 563 @Test testSeeking()564 public void testSeeking() { 565 final AnimatorSet set = new AnimatorSet(); 566 final ValueAnimator a1 = ValueAnimator.ofFloat(0f, 150f); 567 a1.setDuration(150); 568 final ValueAnimator a2 = ValueAnimator.ofFloat(150f, 250f); 569 a2.setDuration(100); 570 final ValueAnimator a3 = ValueAnimator.ofFloat(250f, 300f); 571 a3.setDuration(50); 572 573 a1.setInterpolator(null); 574 a2.setInterpolator(null); 575 a3.setInterpolator(null); 576 577 set.playSequentially(a1, a2, a3); 578 579 set.setCurrentPlayTime(100); 580 assertEquals(100f, (Float) a1.getAnimatedValue(), EPSILON); 581 assertEquals(150f, (Float) a2.getAnimatedValue(), EPSILON); 582 assertEquals(250f, (Float) a3.getAnimatedValue(), EPSILON); 583 584 set.setCurrentPlayTime(280); 585 assertEquals(150f, (Float) a1.getAnimatedValue(), EPSILON); 586 assertEquals(250f, (Float) a2.getAnimatedValue(), EPSILON); 587 assertEquals(280f, (Float) a3.getAnimatedValue(), EPSILON); 588 589 set.start(); 590 sAnimatorTestRule.advanceTimeBy(0); 591 assertEquals(280, set.getCurrentPlayTime()); 592 assertTrue(set.isRunning()); 593 sAnimatorTestRule.advanceTimeBy(20); 594 assertFalse(set.isStarted()); 595 596 // Seek after a run to the middle-ish, and verify the first animator is at the end 597 // value and the 3rd at beginning value, and the 2nd animator is at the seeked value. 598 set.setCurrentPlayTime(200); 599 assertEquals(150f, (Float) a1.getAnimatedValue(), EPSILON); 600 assertEquals(200f, (Float) a2.getAnimatedValue(), EPSILON); 601 assertEquals(250f, (Float) a3.getAnimatedValue(), EPSILON); 602 } 603 604 /** 605 * Testing seeking in an AnimatorSet containing infinite animators. 606 */ 607 @Test testSeekingInfinite()608 public void testSeekingInfinite() { 609 final AnimatorSet set = new AnimatorSet(); 610 final ValueAnimator a1 = ValueAnimator.ofFloat(0f, 100f); 611 a1.setDuration(100); 612 final ValueAnimator a2 = ValueAnimator.ofFloat(100f, 200f); 613 a2.setDuration(100); 614 a2.setRepeatCount(ValueAnimator.INFINITE); 615 a2.setRepeatMode(ValueAnimator.RESTART); 616 617 final ValueAnimator a3 = ValueAnimator.ofFloat(100f, 200f); 618 a3.setDuration(100); 619 a3.setRepeatCount(ValueAnimator.INFINITE); 620 a3.setRepeatMode(ValueAnimator.REVERSE); 621 622 a1.setInterpolator(null); 623 a2.setInterpolator(null); 624 a3.setInterpolator(null); 625 set.play(a1).before(a2); 626 set.play(a1).before(a3); 627 628 set.setCurrentPlayTime(50); 629 assertEquals(50L, set.getCurrentPlayTime()); 630 assertEquals(50f, (Float) a1.getAnimatedValue(), EPSILON); 631 assertEquals(100f, (Float) a2.getAnimatedValue(), EPSILON); 632 assertEquals(100f, (Float) a3.getAnimatedValue(), EPSILON); 633 634 set.setCurrentPlayTime(100); 635 assertEquals(100L, set.getCurrentPlayTime()); 636 assertEquals(100f, (Float) a1.getAnimatedValue(), EPSILON); 637 assertEquals(100f, (Float) a2.getAnimatedValue(), EPSILON); 638 assertEquals(100f, (Float) a3.getAnimatedValue(), EPSILON); 639 640 // Seek to the 1st iteration of the infinite repeat animators, and they should have the 641 // same value. 642 set.setCurrentPlayTime(180); 643 assertEquals(180L, set.getCurrentPlayTime()); 644 assertEquals(100f, (Float) a1.getAnimatedValue(), EPSILON); 645 assertEquals(180f, (Float) a2.getAnimatedValue(), EPSILON); 646 assertEquals(180f, (Float) a3.getAnimatedValue(), EPSILON); 647 648 // Seek to the 2nd iteration of the infinite repeat animators, and they should have 649 // different values as they have different repeat mode. 650 set.setCurrentPlayTime(280); 651 assertEquals(280L, set.getCurrentPlayTime()); 652 assertEquals(100f, (Float) a1.getAnimatedValue(), EPSILON); 653 assertEquals(180f, (Float) a2.getAnimatedValue(), EPSILON); 654 assertEquals(120f, (Float) a3.getAnimatedValue(), EPSILON); 655 656 } 657 658 @UiThreadTest 659 @Test testSeekNested()660 public void testSeekNested() { 661 final AnimatorSet parent = new AnimatorSet(); 662 final ValueAnimator a1 = ValueAnimator.ofFloat(0f, 100f); 663 a1.setDuration(100); 664 final AnimatorSet child = new AnimatorSet(); 665 child.playTogether(a1); 666 final ValueAnimator a2 = ValueAnimator.ofFloat(100f, 200f); 667 a2.setDuration(100); 668 parent.playTogether(child, a2); 669 670 parent.setCurrentPlayTime(50); 671 assertEquals(50f, (float) a1.getAnimatedValue(), EPSILON); 672 assertEquals(150f, (float) a2.getAnimatedValue(), EPSILON); 673 } 674 675 @UiThreadTest 676 @Test testNotifiesAfterEnd()677 public void testNotifiesAfterEnd() { 678 final ValueAnimator animator = ValueAnimator.ofFloat(0, 1); 679 class TestListener extends AnimatorListenerAdapter { 680 public boolean startIsCalled = false; 681 public boolean endIsCalled = false; 682 @Override 683 public void onAnimationStart(@NonNull Animator animation) { 684 assertTrue(animation.isStarted()); 685 assertTrue(animation.isRunning()); 686 startIsCalled = true; 687 } 688 689 @Override 690 public void onAnimationEnd(@NonNull Animator animation) { 691 assertFalse(animation.isRunning()); 692 assertFalse(animation.isStarted()); 693 super.onAnimationEnd(animation); 694 endIsCalled = true; 695 } 696 } 697 TestListener listener = new TestListener(); 698 animator.addListener(listener); 699 700 TestListener setListener = new TestListener(); 701 final AnimatorSet animatorSet = new AnimatorSet(); 702 animatorSet.playTogether(animator); 703 animatorSet.addListener(setListener); 704 705 animatorSet.start(); 706 animator.end(); 707 assertFalse(animator.isStarted()); 708 709 assertTrue(listener.startIsCalled); 710 assertTrue(listener.endIsCalled); 711 assertTrue(setListener.startIsCalled); 712 } 713 714 /** 715 * 716 * This test verifies that custom ValueAnimators will be start()'ed in a set. 717 */ 718 @UiThreadTest 719 @Test testChildAnimatorStartCalled()720 public void testChildAnimatorStartCalled() { 721 class StartListener extends AnimatorListenerAdapter { 722 public boolean mStartCalled = false; 723 @Override 724 public void onAnimationStart(@NonNull Animator anim) { 725 mStartCalled = true; 726 } 727 } 728 729 StartListener l1 = new StartListener(); 730 StartListener l2 = new StartListener(); 731 mAnim1.addListener(l1); 732 mAnim2.addListener(l2); 733 734 AnimatorSet set = new AnimatorSet(); 735 set.playTogether(mAnim1, mAnim2); 736 set.start(); 737 assertTrue(l1.mStartCalled); 738 assertTrue(l2.mStartCalled); 739 } 740 741 /** 742 * This test sets up an AnimatorSet that contains two sequential animations. The first animation 743 * is infinite, the second animation therefore has an infinite start time. This test verifies 744 * that the infinite start time is handled correctly. 745 */ 746 @UiThreadTest 747 @Test testInfiniteStartTime()748 public void testInfiniteStartTime() { 749 ValueAnimator a1 = ValueAnimator.ofFloat(0f, 1f); 750 a1.setRepeatCount(ValueAnimator.INFINITE); 751 ValueAnimator a2 = ValueAnimator.ofFloat(0f, 1f); 752 753 AnimatorSet set = new AnimatorSet(); 754 set.playSequentially(a1, a2); 755 756 set.start(); 757 758 assertEquals(Animator.DURATION_INFINITE, set.getTotalDuration()); 759 760 set.end(); 761 } 762 763 /** 764 * This test sets up 10 animators playing together. We expect the start time for all animators 765 * to be the same. 766 */ 767 @UiThreadTest 768 @Test testMultipleAnimatorsPlayTogether()769 public void testMultipleAnimatorsPlayTogether() { 770 Animator[] animators = new Animator[10]; 771 for (int i = 0; i < 10; i++) { 772 animators[i] = ValueAnimator.ofFloat(0f, 1f); 773 animators[i].setDuration(100 + i * 100); 774 } 775 AnimatorSet set = new AnimatorSet(); 776 set.playTogether(animators); 777 set.setStartDelay(80); 778 779 set.start(); 780 sAnimatorTestRule.advanceTimeBy(0); 781 assertTrue(set.isStarted()); 782 assertFalse(set.isRunning()); 783 sAnimatorTestRule.advanceTimeBy(80); 784 for (int i = 0; i < 10; i++) { 785 assertTrue(animators[i].isRunning()); 786 sAnimatorTestRule.advanceTimeBy(100); 787 assertFalse(animators[i].isStarted()); 788 } 789 790 // The set should finish by now. 791 assertFalse(set.isStarted()); 792 } 793 794 @UiThreadTest 795 @Test testGetChildAnimations()796 public void testGetChildAnimations() { 797 Animator[] animatorArray = {mAnim1, mAnim2}; 798 799 mAnimatorSet = new AnimatorSet(); 800 mAnimatorSet.getChildAnimations(); 801 assertEquals(0, mAnimatorSet.getChildAnimations().size()); 802 mAnimatorSet.playSequentially(animatorArray); 803 assertEquals(2, mAnimatorSet.getChildAnimations().size()); 804 } 805 806 /** 807 * 808 */ 809 @UiThreadTest 810 @Test testSetInterpolator()811 public void testSetInterpolator() { 812 mAnim1.setRepeatCount(ValueAnimator.INFINITE); 813 Animator[] animatorArray = {mAnim1, mAnim2}; 814 815 Interpolator interpolator = new AccelerateDecelerateInterpolator(); 816 mAnimatorSet = new AnimatorSet(); 817 mAnimatorSet.playTogether(animatorArray); 818 mAnimatorSet.setInterpolator(interpolator); 819 820 assertFalse(mAnimatorSet.isRunning()); 821 mAnimatorSet.start(); 822 823 ArrayList<Animator> animatorList = mAnimatorSet.getChildAnimations(); 824 assertEquals(interpolator, animatorList.get(0).getInterpolator()); 825 assertEquals(interpolator, animatorList.get(1).getInterpolator()); 826 mAnimatorSet.cancel(); 827 } 828 829 @UiThreadTest 830 @Test testMultipleAnimatorsSingleProperty()831 public void testMultipleAnimatorsSingleProperty() { 832 final SampleTarget target = new SampleTarget(); 833 final ObjectAnimator a1 = ObjectAnimator.ofFloat(target, SampleTarget.VALUE, 0f, 1000f); 834 a1.setDuration(1000); 835 a1.setInterpolator(new LinearInterpolator()); 836 final ObjectAnimator a2 = ObjectAnimator.ofFloat(target, SampleTarget.VALUE, 1000f, 2000f); 837 a2.setDuration(1000); 838 a2.setStartDelay(1000); 839 a2.setInterpolator(new LinearInterpolator()); 840 final AnimatorSet set = new AnimatorSet(); 841 set.playTogether(a1, a2); 842 843 set.start(); 844 845 final float delta = 0.001f; 846 assertEquals(0f, target.mValue, delta); 847 848 sAnimatorTestRule.advanceTimeBy(500); 849 assertEquals(500f, (float) a1.getAnimatedValue(), delta); 850 assertEquals(500f, target.mValue, delta); 851 852 sAnimatorTestRule.advanceTimeBy(1000); 853 assertEquals(1500f, target.mValue, delta); 854 855 sAnimatorTestRule.advanceTimeBy(5000); 856 assertEquals(2000f, target.mValue, delta); 857 assertFalse(set.isRunning()); 858 859 // Rewind 860 set.setCurrentPlayTime(1500); 861 assertEquals(1500f, target.mValue, delta); 862 863 set.setCurrentPlayTime(500); 864 assertEquals(500f, target.mValue, delta); 865 } 866 867 static class SampleTarget { 868 869 static final Property<SampleTarget, Float> VALUE = new FloatProperty<SampleTarget>() { 870 @Override 871 public void setValue(@NonNull SampleTarget object, float value) { 872 object.mValue = value; 873 } 874 875 @Override 876 public Float get(SampleTarget sampleTarget) { 877 return sampleTarget.mValue; 878 } 879 }; 880 881 float mValue; 882 } 883 884 static class AnimEvent { 885 enum EventType { 886 START, 887 END 888 } 889 final EventType mType; 890 final Animator mAnim; AnimEvent(EventType type, Animator anim)891 AnimEvent(EventType type, Animator anim) { 892 mType = type; 893 mAnim = anim; 894 } 895 } 896 } 897