1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package android.animation.cts; 17 18 import static com.android.compatibility.common.util.CtsMockitoUtils.within; 19 20 import static org.junit.Assert.assertEquals; 21 import static org.junit.Assert.assertFalse; 22 import static org.junit.Assert.assertSame; 23 import static org.junit.Assert.assertTrue; 24 import static org.mockito.Mockito.any; 25 import static org.mockito.Mockito.mock; 26 import static org.mockito.Mockito.never; 27 import static org.mockito.Mockito.timeout; 28 import static org.mockito.Mockito.times; 29 import static org.mockito.Mockito.verify; 30 31 import android.animation.Animator; 32 import android.animation.AnimatorListenerAdapter; 33 import android.animation.AnimatorSet; 34 import android.animation.ObjectAnimator; 35 import android.animation.TimeInterpolator; 36 import android.animation.ValueAnimator; 37 import android.os.SystemClock; 38 import android.view.View; 39 import android.view.animation.AccelerateDecelerateInterpolator; 40 import android.view.animation.AccelerateInterpolator; 41 import android.view.animation.LinearInterpolator; 42 43 import androidx.annotation.NonNull; 44 import androidx.test.InstrumentationRegistry; 45 import androidx.test.filters.MediumTest; 46 import androidx.test.rule.ActivityTestRule; 47 import androidx.test.runner.AndroidJUnit4; 48 49 import org.junit.After; 50 import org.junit.Before; 51 import org.junit.Rule; 52 import org.junit.Test; 53 import org.junit.runner.RunWith; 54 55 import java.util.ArrayList; 56 import java.util.HashSet; 57 import java.util.List; 58 import java.util.Set; 59 import java.util.concurrent.CountDownLatch; 60 import java.util.concurrent.TimeUnit; 61 62 @MediumTest 63 @RunWith(AndroidJUnit4.class) 64 public class AnimatorSetTest { 65 private AnimationActivity mActivity; 66 private AnimatorSet mAnimatorSet; 67 private float mPreviousDurationScale = 1.0f; 68 private long mDuration = 1000; 69 private Object object; 70 private ObjectAnimator yAnimator; 71 private ObjectAnimator xAnimator; 72 Set<Integer> identityHashes = new HashSet<>(); 73 private static final float EPSILON = 0.001f; 74 75 @Rule 76 public ActivityTestRule<AnimationActivity> mActivityRule = 77 new ActivityTestRule<>(AnimationActivity.class); 78 79 @Before setup()80 public void setup() { 81 InstrumentationRegistry.getInstrumentation().setInTouchMode(false); 82 mActivity = mActivityRule.getActivity(); 83 mPreviousDurationScale = ValueAnimator.getDurationScale(); 84 ValueAnimator.setDurationScale(1.0f); 85 object = mActivity.view.newBall; 86 yAnimator = getYAnimator(object); 87 xAnimator = getXAnimator(object); 88 } 89 90 @After tearDown()91 public void tearDown() { 92 ValueAnimator.setDurationScale(mPreviousDurationScale); 93 } 94 95 @Test testPlaySequentially()96 public void testPlaySequentially() throws Throwable { 97 xAnimator.setRepeatCount(0); 98 yAnimator.setRepeatCount(0); 99 xAnimator.setDuration(50); 100 yAnimator.setDuration(50); 101 List<Animator> animators = new ArrayList<Animator>(); 102 animators.add(xAnimator); 103 animators.add(yAnimator); 104 mAnimatorSet = new AnimatorSet(); 105 mAnimatorSet.playSequentially(animators); 106 verifySequentialPlayOrder(mAnimatorSet, new Animator[] {xAnimator, yAnimator}); 107 108 ValueAnimator anim1 = ValueAnimator.ofFloat(0f, 1f); 109 ValueAnimator anim2 = ValueAnimator.ofInt(0, 100); 110 anim1.setDuration(50); 111 anim2.setDuration(50); 112 AnimatorSet set = new AnimatorSet(); 113 set.playSequentially(anim1, anim2); 114 verifySequentialPlayOrder(set, new Animator[] {anim1, anim2}); 115 } 116 117 /** 118 * Start the animator, and verify the animators are played sequentially in the order that is 119 * defined in the array. 120 * 121 * @param set AnimatorSet to be started and verified 122 * @param animators animators that we put in the AnimatorSet, in the order that they'll play 123 */ verifySequentialPlayOrder(final AnimatorSet set, Animator[] animators)124 private void verifySequentialPlayOrder(final AnimatorSet set, Animator[] animators) 125 throws Throwable { 126 127 final MyListener[] listeners = new MyListener[animators.length]; 128 for (int i = 0; i < animators.length; i++) { 129 if (i == 0) { 130 listeners[i] = new MyListener(); 131 } else { 132 final int current = i; 133 listeners[i] = new MyListener() { 134 @Override 135 public void onAnimationStart(Animator anim) { 136 super.onAnimationStart(anim); 137 // Check that the previous animator has finished. 138 assertTrue(listeners[current - 1].mEndIsCalled); 139 } 140 }; 141 } 142 animators[i].addListener(listeners[i]); 143 } 144 145 final CountDownLatch startLatch = new CountDownLatch(1); 146 final CountDownLatch endLatch = new CountDownLatch(1); 147 148 set.addListener(new MyListener() { 149 @Override 150 public void onAnimationEnd(Animator anim) { 151 endLatch.countDown(); 152 } 153 }); 154 155 long totalDuration = set.getTotalDuration(); 156 assertFalse(set.isRunning()); 157 mActivityRule.runOnUiThread(() -> { 158 set.start(); 159 startLatch.countDown(); 160 }); 161 162 // Set timeout to 100ms, if current count reaches 0 before the timeout, startLatch.await(...) 163 // will return immediately. 164 assertTrue(startLatch.await(100, TimeUnit.MILLISECONDS)); 165 assertTrue(set.isRunning()); 166 assertTrue(endLatch.await(totalDuration * 2, TimeUnit.MILLISECONDS)); 167 // Check that all the animators have finished. 168 for (int i = 0; i < listeners.length; i++) { 169 assertTrue(listeners[i].mEndIsCalled); 170 } 171 172 // Now reverse the animations and verify whether the play order is reversed. 173 for (int i = 0; i < animators.length; i++) { 174 if (i == animators.length - 1) { 175 listeners[i] = new MyListener(); 176 } else { 177 final int current = i; 178 listeners[i] = new MyListener() { 179 @Override 180 public void onAnimationStart(Animator anim) { 181 super.onAnimationStart(anim); 182 // Check that the previous animator has finished. 183 assertTrue(listeners[current + 1].mEndIsCalled); 184 } 185 }; 186 } 187 animators[i].removeAllListeners(); 188 animators[i].addListener(listeners[i]); 189 } 190 191 mActivityRule.runOnUiThread(() -> { 192 set.reverse(); 193 startLatch.countDown(); 194 }); 195 196 // Set timeout to 100ms, if current count reaches 0 before the timeout, startLatch.await(..) 197 // will return immediately. 198 assertTrue(startLatch.await(100, TimeUnit.MILLISECONDS)); 199 assertTrue(set.isRunning()); 200 assertTrue(endLatch.await(totalDuration * 2, TimeUnit.MILLISECONDS)); 201 202 } 203 204 @Test testPlayTogether()205 public void testPlayTogether() throws Throwable { 206 xAnimator.setRepeatCount(ValueAnimator.INFINITE); 207 Animator[] animatorArray = {xAnimator, yAnimator}; 208 209 mAnimatorSet = new AnimatorSet(); 210 mAnimatorSet.playTogether(animatorArray); 211 212 assertFalse(mAnimatorSet.isRunning()); 213 assertFalse(xAnimator.isRunning()); 214 assertFalse(yAnimator.isRunning()); 215 startAnimation(mAnimatorSet); 216 SystemClock.sleep(100); 217 assertTrue(mAnimatorSet.isRunning()); 218 assertTrue(xAnimator.isRunning()); 219 assertTrue(yAnimator.isRunning()); 220 221 // Now assemble another animator set 222 ValueAnimator anim1 = ValueAnimator.ofFloat(0f, 100f); 223 ValueAnimator anim2 = ValueAnimator.ofFloat(10f, 100f); 224 AnimatorSet set = new AnimatorSet(); 225 set.playTogether(anim1, anim2); 226 227 assertFalse(set.isRunning()); 228 assertFalse(anim1.isRunning()); 229 assertFalse(anim2.isRunning()); 230 startAnimation(set); 231 SystemClock.sleep(100); 232 assertTrue(set.isRunning()); 233 assertTrue(anim1.isRunning()); 234 assertTrue(anim2.isRunning()); 235 } 236 237 @Test testPlayBeforeAfter()238 public void testPlayBeforeAfter() throws Throwable { 239 xAnimator.setRepeatCount(0); 240 yAnimator.setRepeatCount(0); 241 final ValueAnimator zAnimator = ValueAnimator.ofFloat(0f, 100f); 242 243 xAnimator.setDuration(50); 244 yAnimator.setDuration(50); 245 zAnimator.setDuration(50); 246 247 AnimatorSet set = new AnimatorSet(); 248 set.play(yAnimator).before(zAnimator).after(xAnimator); 249 250 verifySequentialPlayOrder(set, new Animator[] {xAnimator, yAnimator, zAnimator}); 251 } 252 253 @Test testListenerCallbackOnEmptySet()254 public void testListenerCallbackOnEmptySet() throws Throwable { 255 // Create an AnimatorSet that only contains one empty AnimatorSet, and checks the callback 256 // sequence by checking the time stamps of the callbacks. 257 final AnimatorSet emptySet = new AnimatorSet(); 258 final AnimatorSet set = new AnimatorSet(); 259 set.play(emptySet); 260 MyListener listener = new MyListener() { 261 long startTime = 0; 262 long endTime = 0; 263 @Override 264 public void onAnimationStart(Animator animation) { 265 super.onAnimationStart(animation); 266 startTime = SystemClock.currentThreadTimeMillis(); 267 } 268 269 @Override 270 public void onAnimationEnd(Animator animation) { 271 super.onAnimationEnd(animation); 272 endTime = SystemClock.currentThreadTimeMillis(); 273 assertTrue(endTime >= startTime); 274 assertTrue(startTime != 0); 275 } 276 }; 277 set.addListener(listener); 278 mActivityRule.runOnUiThread(() -> { 279 set.start(); 280 }); 281 assertTrue(listener.mStartIsCalled); 282 assertTrue(listener.mEndIsCalled); 283 } 284 285 @Test testPauseAndResume()286 public void testPauseAndResume() throws Throwable { 287 final AnimatorSet set = new AnimatorSet(); 288 ValueAnimator a1 = ValueAnimator.ofFloat(0f, 100f); 289 a1.setDuration(50); 290 ValueAnimator a2 = ValueAnimator.ofFloat(0f, 100f); 291 a2.setDuration(50); 292 a1.addListener(new AnimatorListenerAdapter() { 293 @Override 294 public void onAnimationStart(Animator animation) { 295 // Pause non-delayed set once the child animator starts 296 set.pause(); 297 } 298 }); 299 set.playTogether(a1, a2); 300 301 final AnimatorSet delayedSet = new AnimatorSet(); 302 ValueAnimator a3 = ValueAnimator.ofFloat(0f, 100f); 303 a3.setDuration(50); 304 ValueAnimator a4 = ValueAnimator.ofFloat(0f, 100f); 305 a4.setDuration(50); 306 delayedSet.playSequentially(a3, a4); 307 delayedSet.setStartDelay(50); 308 309 MyListener l1 = new MyListener(); 310 MyListener l2 = new MyListener(); 311 set.addListener(l1); 312 delayedSet.addListener(l2); 313 314 mActivityRule.runOnUiThread(() -> { 315 set.start(); 316 delayedSet.start(); 317 318 // Pause the delayed set during start delay 319 delayedSet.pause(); 320 }); 321 322 // Sleep long enough so that if the sets are not properly paused, they would have 323 // finished. 324 SystemClock.sleep(300); 325 // Verify that both sets have been paused and *not* finished. 326 assertTrue(set.isPaused()); 327 assertTrue(delayedSet.isPaused()); 328 assertTrue(l1.mStartIsCalled); 329 assertTrue(l2.mStartIsCalled); 330 assertFalse(l1.mEndIsCalled); 331 assertFalse(l2.mEndIsCalled); 332 333 mActivityRule.runOnUiThread(() -> { 334 set.resume(); 335 delayedSet.resume(); 336 }); 337 SystemClock.sleep(300); 338 339 assertFalse(set.isPaused()); 340 assertFalse(delayedSet.isPaused()); 341 assertTrue(l1.mEndIsCalled); 342 assertTrue(l2.mEndIsCalled); 343 } 344 345 @Test testPauseBeforeStart()346 public void testPauseBeforeStart() throws Throwable { 347 final AnimatorSet set = new AnimatorSet(); 348 ValueAnimator a1 = ValueAnimator.ofFloat(0f, 100f); 349 a1.setDuration(50); 350 ValueAnimator a2 = ValueAnimator.ofFloat(0f, 100f); 351 a2.setDuration(50); 352 set.setStartDelay(50); 353 set.playSequentially(a1, a2); 354 355 final MyListener listener = new MyListener(); 356 set.addListener(listener); 357 358 mActivityRule.runOnUiThread(() -> { 359 // Pause animator set before calling start() 360 set.pause(); 361 // Verify that pause should have no effect on a not-yet-started animator. 362 assertFalse(set.isPaused()); 363 set.start(); 364 }); 365 SystemClock.sleep(300); 366 367 // Animator set should finish running by now since it's not paused. 368 assertTrue(listener.mStartIsCalled); 369 assertTrue(listener.mEndIsCalled); 370 } 371 372 @Test testSeekAfterPause()373 public void testSeekAfterPause() throws Throwable { 374 final AnimatorSet set = new AnimatorSet(); 375 ValueAnimator a1 = ValueAnimator.ofFloat(0f, 50f); 376 a1.setDuration(50); 377 ValueAnimator a2 = ValueAnimator.ofFloat(50, 100f); 378 a2.setDuration(50); 379 set.playSequentially(a1, a2); 380 set.setInterpolator(new LinearInterpolator()); 381 382 mActivityRule.runOnUiThread(() -> { 383 set.start(); 384 set.pause(); 385 set.setCurrentPlayTime(60); 386 assertEquals((long) set.getCurrentPlayTime(), 60); 387 assertEquals((float) a1.getAnimatedValue(), 50f, EPSILON); 388 assertEquals((float) a2.getAnimatedValue(), 60f, EPSILON); 389 390 set.setCurrentPlayTime(40); 391 assertEquals((long) set.getCurrentPlayTime(), 40); 392 assertEquals((float) a1.getAnimatedValue(), 40f, EPSILON); 393 assertEquals((float) a2.getAnimatedValue(), 50f, EPSILON); 394 395 set.cancel(); 396 }); 397 } 398 399 @Test testDuration()400 public void testDuration() throws Throwable { 401 xAnimator.setRepeatCount(ValueAnimator.INFINITE); 402 Animator[] animatorArray = { xAnimator, yAnimator }; 403 404 mAnimatorSet = new AnimatorSet(); 405 mAnimatorSet.playTogether(animatorArray); 406 mAnimatorSet.setDuration(1000); 407 408 startAnimation(mAnimatorSet); 409 SystemClock.sleep(100); 410 assertEquals(mAnimatorSet.getDuration(), 1000); 411 } 412 413 @Test testStartDelay()414 public void testStartDelay() throws Throwable { 415 xAnimator.setRepeatCount(ValueAnimator.INFINITE); 416 Animator[] animatorArray = { xAnimator, yAnimator }; 417 418 mAnimatorSet = new AnimatorSet(); 419 mAnimatorSet.playTogether(animatorArray); 420 mAnimatorSet.setStartDelay(10); 421 422 startAnimation(mAnimatorSet); 423 SystemClock.sleep(100); 424 assertEquals(mAnimatorSet.getStartDelay(), 10); 425 } 426 427 /** 428 * This test sets up an AnimatorSet with start delay. One of the child animators also has 429 * start delay. We then verify that start delay was handled correctly on both AnimatorSet 430 * and individual animator level. 431 */ 432 @Test testReverseWithStartDelay()433 public void testReverseWithStartDelay() throws Throwable { 434 ValueAnimator a1 = ValueAnimator.ofFloat(0f, 1f); 435 a1.setDuration(200); 436 Animator.AnimatorListener listener1 = mock(AnimatorListenerAdapter.class); 437 a1.addListener(listener1); 438 439 ValueAnimator a2 = ValueAnimator.ofFloat(1f, 2f); 440 a2.setDuration(200); 441 // Set start delay on a2 so that the delay is passed 100ms after a1 is finished. 442 a2.setStartDelay(300); 443 Animator.AnimatorListener listener = mock(AnimatorListenerAdapter.class); 444 a2.addListener(listener); 445 446 a2.addListener(new AnimatorListenerAdapter() { 447 @Override 448 public void onAnimationEnd(Animator animation, boolean inReverse) { 449 assertTrue(inReverse); 450 // By the time a2 finishes reversing, a1 should not have started. 451 assertFalse(a1.isStarted()); 452 } 453 }); 454 455 AnimatorSet set = new AnimatorSet(); 456 set.playTogether(a1, a2); 457 set.setStartDelay(1000); 458 Animator.AnimatorListener setListener = mock(AnimatorListenerAdapter.class); 459 set.addListener(setListener); 460 mActivityRule.runOnUiThread(() -> { 461 set.reverse(); 462 assertTrue(a2.isStarted()); 463 assertTrue(a2.isRunning()); 464 }); 465 466 // a2 should finish 200ms after reverse started 467 verify(listener, within(300)).onAnimationEnd(a2, true); 468 // When a2 finishes, a1 should not have started yet 469 verify(listener1, never()).onAnimationStart(a1, true); 470 471 // The whole set should finish within 500ms, i.e. 300ms after a2 is finished. This verifies 472 // that the AnimatorSet didn't mistakenly use its start delay in the reverse run. 473 verify(setListener, within(400)).onAnimationEnd(set, true); 474 verify(listener1, times(1)).onAnimationEnd(a1, true); 475 476 } 477 478 /** 479 * Test that duration scale is handled correctly in the AnimatorSet. 480 */ 481 @Test testZeroDurationScale()482 public void testZeroDurationScale() throws Throwable { 483 ValueAnimator.setDurationScale(0); 484 485 ValueAnimator a1 = ValueAnimator.ofFloat(0f, 1f); 486 a1.setDuration(200); 487 Animator.AnimatorListener listener1 = mock(AnimatorListenerAdapter.class); 488 a1.addListener(listener1); 489 490 ValueAnimator a2 = ValueAnimator.ofFloat(1f, 2f); 491 a2.setDuration(200); 492 // Set start delay on a2 so that the delay is passed 100ms after a1 is finished. 493 a2.setStartDelay(300); 494 Animator.AnimatorListener listener2 = mock(AnimatorListenerAdapter.class); 495 a2.addListener(listener2); 496 497 AnimatorSet set = new AnimatorSet(); 498 set.playSequentially(a1, a2); 499 set.setStartDelay(1000); 500 Animator.AnimatorListener setListener = mock(AnimatorListenerAdapter.class); 501 set.addListener(setListener); 502 503 mActivityRule.runOnUiThread(() -> { 504 set.start(); 505 verify(setListener, times(0)).onAnimationEnd(any(AnimatorSet.class), 506 any(boolean.class)); 507 }); 508 verify(setListener, within(100)).onAnimationEnd(set, false); 509 verify(listener1, times(1)).onAnimationEnd(a1, false); 510 verify(listener2, times(1)).onAnimationEnd(a2, false); 511 } 512 513 /** 514 * Test that non-zero duration scale is handled correctly in the AnimatorSet. 515 */ 516 @Test testDurationScale()517 public void testDurationScale() throws Throwable { 518 // Change the duration scale to 3 519 ValueAnimator.setDurationScale(3f); 520 521 ValueAnimator a1 = ValueAnimator.ofFloat(0f, 1f); 522 a1.setDuration(100); 523 Animator.AnimatorListener listener1 = mock(AnimatorListenerAdapter.class); 524 a1.addListener(listener1); 525 526 ValueAnimator a2 = ValueAnimator.ofFloat(1f, 2f); 527 a2.setDuration(100); 528 // Set start delay on a2 so that the delay is passed 100ms after a1 is finished. 529 a2.setStartDelay(200); 530 Animator.AnimatorListener listener2 = mock(AnimatorListenerAdapter.class); 531 a2.addListener(listener2); 532 533 AnimatorSet set = new AnimatorSet(); 534 set.playSequentially(a1, a2); 535 Animator.AnimatorListener setListener = mock(AnimatorListenerAdapter.class); 536 set.addListener(setListener); 537 set.setStartDelay(200); 538 539 mActivityRule.runOnUiThread(() -> { 540 set.start(); 541 }); 542 543 // Sleep for part of the start delay and check that no child animator has started, to verify 544 // that the duration scale has been properly scaled. 545 SystemClock.sleep(400); 546 // start delay of the set should be scaled to 600ms 547 verify(listener1, never()).onAnimationStart(a1, false); 548 verify(listener2, never()).onAnimationStart(a2, false); 549 550 verify(listener1, within(400)).onAnimationStart(a1, false); 551 // Verify that a1 finish in ~300ms (3x its defined duration) 552 verify(listener1, within(500)).onAnimationEnd(a1, false); 553 554 // a2 should be in the delayed stage after a1 is finished 555 assertTrue(a2.isStarted()); 556 assertFalse(a2.isRunning()); 557 558 verify(listener2, within(800)).onAnimationStart(a2, false); 559 assertTrue(a2.isRunning()); 560 561 // Verify that the AnimatorSet has finished within 1650ms since the start of the animation. 562 // The duration of the set is 500ms, duration scale = 3. 563 verify(setListener, within(500)).onAnimationEnd(set, false); 564 verify(listener1, times(1)).onAnimationEnd(a1, false); 565 verify(listener2, times(1)).onAnimationEnd(a2, false); 566 } 567 568 /** 569 * This test sets up 10 animators playing together. We expect the start time for all animators 570 * to be the same. 571 */ 572 @Test testMultipleAnimatorsPlayTogether()573 public void testMultipleAnimatorsPlayTogether() throws Throwable { 574 Animator[] animators = new Animator[10]; 575 for (int i = 0; i < 10; i++) { 576 animators[i] = ValueAnimator.ofFloat(0f, 1f); 577 } 578 AnimatorSet set = new AnimatorSet(); 579 set.playTogether(animators); 580 set.setStartDelay(80); 581 582 Animator.AnimatorListener setListener = mock(AnimatorListenerAdapter.class); 583 set.addListener(setListener); 584 mActivityRule.runOnUiThread(() -> { 585 set.start(); 586 }); 587 SystemClock.sleep(150); 588 for (int i = 0; i < 10; i++) { 589 assertTrue(animators[i].isRunning()); 590 } 591 592 verify(setListener, within(400)).onAnimationEnd(set, false); 593 } 594 595 @Test testGetChildAnimations()596 public void testGetChildAnimations() throws Throwable { 597 Animator[] animatorArray = { xAnimator, yAnimator }; 598 599 mAnimatorSet = new AnimatorSet(); 600 mAnimatorSet.getChildAnimations(); 601 assertEquals(0, mAnimatorSet.getChildAnimations().size()); 602 mAnimatorSet.playSequentially(animatorArray); 603 assertEquals(2, mAnimatorSet.getChildAnimations().size()); 604 } 605 606 @Test testSetInterpolator()607 public void testSetInterpolator() throws Throwable { 608 xAnimator.setRepeatCount(ValueAnimator.INFINITE); 609 Animator[] animatorArray = {xAnimator, yAnimator}; 610 TimeInterpolator interpolator = new AccelerateDecelerateInterpolator(); 611 mAnimatorSet = new AnimatorSet(); 612 mAnimatorSet.playTogether(animatorArray); 613 mAnimatorSet.setInterpolator(interpolator); 614 615 assertFalse(mAnimatorSet.isRunning()); 616 startAnimation(mAnimatorSet); 617 SystemClock.sleep(100); 618 619 ArrayList<Animator> animatorList = mAnimatorSet.getChildAnimations(); 620 assertEquals(interpolator, animatorList.get(0).getInterpolator()); 621 assertEquals(interpolator, animatorList.get(1).getInterpolator()); 622 } 623 getXAnimator(Object object)624 private ObjectAnimator getXAnimator(Object object) { 625 String propertyX = "x"; 626 float startX = mActivity.mStartX; 627 float endX = mActivity.mStartX + mActivity.mDeltaX; 628 ObjectAnimator xAnimator = ObjectAnimator.ofFloat(object, propertyX, startX, endX); 629 xAnimator.setDuration(mDuration); 630 xAnimator.setRepeatCount(ValueAnimator.INFINITE); 631 xAnimator.setInterpolator(new AccelerateInterpolator()); 632 xAnimator.setRepeatMode(ValueAnimator.REVERSE); 633 return xAnimator; 634 } 635 getYAnimator(Object object)636 private ObjectAnimator getYAnimator(Object object) { 637 String property = "y"; 638 float startY = mActivity.mStartY; 639 float endY = mActivity.mStartY + mActivity.mDeltaY; 640 ObjectAnimator yAnimator = ObjectAnimator.ofFloat(object, property, startY, endY); 641 yAnimator.setDuration(mDuration); 642 yAnimator.setRepeatCount(2); 643 yAnimator.setInterpolator(new AccelerateInterpolator()); 644 yAnimator.setRepeatMode(ValueAnimator.REVERSE); 645 return yAnimator; 646 } 647 startAnimation(final AnimatorSet animatorSet)648 private void startAnimation(final AnimatorSet animatorSet) throws Throwable { 649 mActivityRule.runOnUiThread(() -> mActivity.startAnimatorSet(animatorSet)); 650 } 651 assertUnique(Object object)652 private void assertUnique(Object object) { 653 assertUnique(object, ""); 654 } 655 assertUnique(Object object, String msg)656 private void assertUnique(Object object, String msg) { 657 final int code = System.identityHashCode(object); 658 assertTrue("object should be unique " + msg + ", obj:" + object, identityHashes.add(code)); 659 660 } 661 662 @Test testClone()663 public void testClone() throws Throwable { 664 final AnimatorSet set1 = new AnimatorSet(); 665 final AnimatorListenerAdapter setListener = new AnimatorListenerAdapter() {}; 666 set1.addListener(setListener); 667 ObjectAnimator animator1 = new ObjectAnimator(); 668 animator1.setDuration(100); 669 animator1.setPropertyName("x"); 670 animator1.setIntValues(5); 671 animator1.setInterpolator(new LinearInterpolator()); 672 AnimatorListenerAdapter listener1 = new AnimatorListenerAdapter(){}; 673 AnimatorListenerAdapter listener2 = new AnimatorListenerAdapter(){}; 674 animator1.addListener(listener1); 675 676 ObjectAnimator animator2 = new ObjectAnimator(); 677 animator2.setDuration(100); 678 animator2.setInterpolator(new LinearInterpolator()); 679 animator2.addListener(listener2); 680 animator2.setPropertyName("y"); 681 animator2.setIntValues(10); 682 683 set1.playTogether(animator1, animator2); 684 685 AnimateObject target = new AnimateObject(); 686 set1.setTarget(target); 687 mActivityRule.runOnUiThread(set1::start); 688 assertTrue(set1.isStarted()); 689 690 animator1.getListeners(); 691 AnimatorSet set2 = set1.clone(); 692 assertFalse(set2.isStarted()); 693 694 assertUnique(set1); 695 assertUnique(animator1); 696 assertUnique(animator2); 697 698 assertUnique(set2); 699 assertEquals(2, set2.getChildAnimations().size()); 700 701 Animator clone1 = set2.getChildAnimations().get(0); 702 Animator clone2 = set2.getChildAnimations().get(1); 703 704 for (Animator animator : set2.getChildAnimations()) { 705 assertUnique(animator); 706 } 707 708 assertTrue(clone1.getListeners().contains(listener1)); 709 assertTrue(clone2.getListeners().contains(listener2)); 710 711 assertTrue(set2.getListeners().contains(setListener)); 712 713 for (Animator.AnimatorListener listener : set1.getListeners()) { 714 assertTrue(set2.getListeners().contains(listener)); 715 } 716 717 assertEquals(animator1.getDuration(), clone1.getDuration()); 718 assertEquals(animator2.getDuration(), clone2.getDuration()); 719 assertSame(animator1.getInterpolator(), clone1.getInterpolator()); 720 assertSame(animator2.getInterpolator(), clone2.getInterpolator()); 721 } 722 723 /** 724 * Testing seeking in an AnimatorSet containing sequential animators. 725 */ 726 @Test testSeeking()727 public void testSeeking() throws Throwable { 728 final AnimatorSet set = new AnimatorSet(); 729 final ValueAnimator a1 = ValueAnimator.ofFloat(0f, 150f); 730 a1.setDuration(150); 731 final ValueAnimator a2 = ValueAnimator.ofFloat(150f, 250f); 732 a2.setDuration(100); 733 final ValueAnimator a3 = ValueAnimator.ofFloat(250f, 300f); 734 a3.setDuration(50); 735 736 a1.setInterpolator(null); 737 a2.setInterpolator(null); 738 a3.setInterpolator(null); 739 740 set.playSequentially(a1, a2, a3); 741 742 set.setCurrentPlayTime(100); 743 assertEquals(100f, (Float) a1.getAnimatedValue(), EPSILON); 744 assertEquals(150f, (Float) a2.getAnimatedValue(), EPSILON); 745 assertEquals(250f, (Float) a3.getAnimatedValue(), EPSILON); 746 747 set.setCurrentPlayTime(280); 748 assertEquals(150f, (Float) a1.getAnimatedValue(), EPSILON); 749 assertEquals(250f, (Float) a2.getAnimatedValue(), EPSILON); 750 assertEquals(280f, (Float) a3.getAnimatedValue(), EPSILON); 751 752 AnimatorListenerAdapter setListener = new AnimatorListenerAdapter() { 753 @Override 754 public void onAnimationEnd(Animator animation) { 755 super.onAnimationEnd(animation); 756 assertEquals(150f, (Float) a1.getAnimatedValue(), EPSILON); 757 assertEquals(250f, (Float) a2.getAnimatedValue(), EPSILON); 758 assertEquals(300f, (Float) a3.getAnimatedValue(), EPSILON); 759 } 760 }; 761 AnimatorListenerAdapter mockListener = mock(AnimatorListenerAdapter.class); 762 set.addListener(setListener); 763 set.addListener(mockListener); 764 mActivityRule.runOnUiThread(() -> { 765 set.start(); 766 }); 767 768 verify(mockListener, within(300)).onAnimationEnd(set, false); 769 770 // Seek after a run to the middle-ish, and verify the first animator is at the end 771 // value and the 3rd at beginning value, and the 2nd animator is at the seeked value. 772 set.setCurrentPlayTime(200); 773 assertEquals(150f, (Float) a1.getAnimatedValue(), EPSILON); 774 assertEquals(200f, (Float) a2.getAnimatedValue(), EPSILON); 775 assertEquals(250f, (Float) a3.getAnimatedValue(), EPSILON); 776 } 777 778 /** 779 * Testing seeking in an AnimatorSet containing infinite animators. 780 */ 781 @Test testSeekingInfinite()782 public void testSeekingInfinite() { 783 final AnimatorSet set = new AnimatorSet(); 784 final ValueAnimator a1 = ValueAnimator.ofFloat(0f, 100f); 785 a1.setDuration(100); 786 final ValueAnimator a2 = ValueAnimator.ofFloat(100f, 200f); 787 a2.setDuration(100); 788 a2.setRepeatCount(ValueAnimator.INFINITE); 789 a2.setRepeatMode(ValueAnimator.RESTART); 790 791 final ValueAnimator a3 = ValueAnimator.ofFloat(100f, 200f); 792 a3.setDuration(100); 793 a3.setRepeatCount(ValueAnimator.INFINITE); 794 a3.setRepeatMode(ValueAnimator.REVERSE); 795 796 a1.setInterpolator(null); 797 a2.setInterpolator(null); 798 a3.setInterpolator(null); 799 set.play(a1).before(a2); 800 set.play(a1).before(a3); 801 802 set.setCurrentPlayTime(50); 803 assertEquals(50f, (Float) a1.getAnimatedValue(), EPSILON); 804 assertEquals(100f, (Float) a2.getAnimatedValue(), EPSILON); 805 assertEquals(100f, (Float) a3.getAnimatedValue(), EPSILON); 806 807 set.setCurrentPlayTime(100); 808 assertEquals(100f, (Float) a1.getAnimatedValue(), EPSILON); 809 assertEquals(100f, (Float) a2.getAnimatedValue(), EPSILON); 810 assertEquals(100f, (Float) a3.getAnimatedValue(), EPSILON); 811 812 // Seek to the 1st iteration of the infinite repeat animators, and they should have the 813 // same value. 814 set.setCurrentPlayTime(180); 815 assertEquals(100f, (Float) a1.getAnimatedValue(), EPSILON); 816 assertEquals(180f, (Float) a2.getAnimatedValue(), EPSILON); 817 assertEquals(180f, (Float) a3.getAnimatedValue(), EPSILON); 818 819 // Seek to the 2nd iteration of the infinite repeat animators, and they should have 820 // different values as they have different repeat mode. 821 set.setCurrentPlayTime(280); 822 assertEquals(100f, (Float) a1.getAnimatedValue(), EPSILON); 823 assertEquals(180f, (Float) a2.getAnimatedValue(), EPSILON); 824 assertEquals(120f, (Float) a3.getAnimatedValue(), EPSILON); 825 826 } 827 828 /** 829 * This test verifies that getCurrentPlayTime() returns the right value. 830 */ 831 @Test testGetCurrentPlayTime()832 public void testGetCurrentPlayTime() throws Throwable { 833 // Setup an AnimatorSet with start delay 834 final AnimatorSet set = new AnimatorSet(); 835 final ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f).setDuration(300); 836 anim.addListener(new AnimatorListenerAdapter() { 837 @Override 838 public void onAnimationStart(Animator animation, boolean inReverse) { 839 assertFalse(inReverse); 840 assertEquals(200, set.getCurrentPlayTime()); 841 } 842 }); 843 set.play(anim); 844 set.setStartDelay(100); 845 846 Animator.AnimatorListener setListener = mock(AnimatorListenerAdapter.class); 847 set.addListener(setListener); 848 849 // Set a seek time and verify, before start 850 set.setCurrentPlayTime(20); 851 assertEquals(20, set.getCurrentPlayTime()); 852 853 // Now start() should start right away from the seeked position, skipping the delay. 854 mActivityRule.runOnUiThread(() -> { 855 set.setCurrentPlayTime(200); 856 set.start(); 857 assertEquals(200, set.getCurrentPlayTime()); 858 }); 859 860 // When animation is seeked to 200ms, it should take another 100ms to end. 861 verify(setListener, within(200)).onAnimationEnd(set, false); 862 } 863 864 @Test testNotifiesAfterEnd()865 public void testNotifiesAfterEnd() throws Throwable { 866 final ValueAnimator animator = ValueAnimator.ofFloat(0, 1); 867 Animator.AnimatorListener listener = new AnimatorListenerAdapter() { 868 @Override 869 public void onAnimationStart(Animator animation) { 870 assertTrue(animation.isStarted()); 871 assertTrue(animation.isRunning()); 872 } 873 874 @Override 875 public void onAnimationEnd(Animator animation) { 876 assertFalse(animation.isRunning()); 877 assertFalse(animation.isStarted()); 878 super.onAnimationEnd(animation); 879 } 880 }; 881 animator.addListener(listener); 882 final AnimatorSet animatorSet = new AnimatorSet(); 883 animatorSet.playTogether(animator); 884 animatorSet.addListener(listener); 885 mActivityRule.runOnUiThread(() -> { 886 animatorSet.start(); 887 animator.end(); 888 assertFalse(animator.isStarted()); 889 }); 890 } 891 892 /** 893 * Test that when a child animator is being manipulated outside of an AnimatorSet, by the time 894 * AnimatorSet starts, it will not be affected, and all the child animators would start at their 895 * scheduled start time. 896 */ 897 @Test testManipulateChildOutsideOfSet()898 public void testManipulateChildOutsideOfSet() throws Throwable { 899 final ValueAnimator fadeIn = ObjectAnimator.ofFloat(mActivity.view, View.ALPHA, 0f, 1f); 900 fadeIn.setDuration(200); 901 final ValueAnimator fadeOut = ObjectAnimator.ofFloat(mActivity.view, View.ALPHA, 1f, 0f); 902 fadeOut.setDuration(200); 903 904 ValueAnimator.AnimatorUpdateListener listener = mock( 905 ValueAnimator.AnimatorUpdateListener.class); 906 fadeIn.addUpdateListener(listener); 907 908 AnimatorSet show = new AnimatorSet(); 909 show.play(fadeIn); 910 911 AnimatorSet hideNShow = new AnimatorSet(); 912 hideNShow.play(fadeIn).after(fadeOut); 913 914 mActivityRule.runOnUiThread(() -> 915 show.start() 916 ); 917 918 verify(listener, timeout(100).atLeast(2)).onAnimationUpdate(fadeIn); 919 920 AnimatorListenerAdapter adapter = mock(AnimatorListenerAdapter.class); 921 hideNShow.addListener(adapter); 922 // Start hideNShow after fadeIn is started for 100ms 923 mActivityRule.runOnUiThread(() -> 924 hideNShow.start() 925 ); 926 927 verify(adapter, timeout(800)).onAnimationEnd(hideNShow, false); 928 // Now that the hideNShow finished we need to check whether the fadeIn animation ran again. 929 assertEquals(1f, mActivity.view.getAlpha(), 0); 930 931 } 932 933 /** 934 * 935 * This test verifies that custom ValueAnimators will be start()'ed in a set. 936 */ 937 @Test testChildAnimatorStartCalled()938 public void testChildAnimatorStartCalled() throws Throwable { 939 MyValueAnimator a1 = new MyValueAnimator(); 940 MyValueAnimator a2 = new MyValueAnimator(); 941 AnimatorSet set = new AnimatorSet(); 942 set.playTogether(a1, a2); 943 mActivityRule.runOnUiThread(() -> { 944 set.start(); 945 assertTrue(a1.mStartCalled); 946 assertTrue(a2.mStartCalled); 947 }); 948 } 949 950 @Test seekSequentially()951 public void seekSequentially() { 952 AnimatorSet animatorSet = new AnimatorSet(); 953 animatorSet.setStartDelay(10); 954 ValueAnimator animator1 = ValueAnimator.ofFloat(0f, 1f); 955 animator1.setInterpolator(null); 956 animator1.setStartDelay(5); 957 ValueAnimator animator2 = ValueAnimator.ofFloat(0f, 1f); 958 animator2.setInterpolator(null); 959 animator2.setStartDelay(5); 960 animatorSet.playSequentially(animator1, animator2); 961 animatorSet.setCurrentPlayTime(1); 962 assertEquals(1L, animatorSet.getCurrentPlayTime()); 963 assertEquals(0f, (float) animator1.getAnimatedValue(), EPSILON); 964 assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON); 965 animatorSet.setCurrentPlayTime(15); 966 assertEquals(15L, animatorSet.getCurrentPlayTime()); 967 assertEquals(0f, (float) animator1.getAnimatedValue(), EPSILON); 968 assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON); 969 animatorSet.setCurrentPlayTime(17); 970 assertEquals(17L, animatorSet.getCurrentPlayTime()); 971 assertEquals(2f / 300f, (float) animator1.getAnimatedValue(), EPSILON); 972 assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON); 973 animatorSet.setCurrentPlayTime(316); 974 assertEquals(316, animatorSet.getCurrentPlayTime()); 975 assertEquals(1f, (float) animator1.getAnimatedValue(), EPSILON); 976 assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON); 977 animatorSet.setCurrentPlayTime(320); 978 assertEquals(320, animatorSet.getCurrentPlayTime()); 979 assertEquals(1f, (float) animator1.getAnimatedValue(), EPSILON); 980 assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON); 981 animatorSet.setCurrentPlayTime(321); 982 assertEquals(321, animatorSet.getCurrentPlayTime()); 983 assertEquals(1f, (float) animator1.getAnimatedValue(), EPSILON); 984 assertEquals(1f / 300f, (float) animator2.getAnimatedValue(), EPSILON); 985 animatorSet.setCurrentPlayTime(320); 986 assertEquals(320, animatorSet.getCurrentPlayTime()); 987 assertEquals(1f, (float) animator1.getAnimatedValue(), EPSILON); 988 assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON); 989 animatorSet.setCurrentPlayTime(314); 990 assertEquals(314, animatorSet.getCurrentPlayTime()); 991 assertEquals(299f / 300f, (float) animator1.getAnimatedValue(), EPSILON); 992 assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON); 993 } 994 995 @Test seekSequentiallyWithRepeats()996 public void seekSequentiallyWithRepeats() { 997 AnimatorSet animatorSet = new AnimatorSet(); 998 ValueAnimator animator1 = ValueAnimator.ofFloat(0f, 1f); 999 animator1.setInterpolator(null); 1000 animator1.setRepeatCount(1); 1001 ValueAnimator animator2 = ValueAnimator.ofFloat(0f, 1f); 1002 animator2.setInterpolator(null); 1003 animator2.setRepeatCount(ValueAnimator.INFINITE); 1004 animatorSet.playSequentially(animator1, animator2); 1005 animatorSet.setCurrentPlayTime(1); 1006 assertEquals(1L, animatorSet.getCurrentPlayTime()); 1007 assertEquals(1f / 300f, (float) animator1.getAnimatedValue(), EPSILON); 1008 assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON); 1009 animatorSet.setCurrentPlayTime(301); 1010 assertEquals(301, animatorSet.getCurrentPlayTime()); 1011 assertEquals(1f / 300f, (float) animator1.getAnimatedValue(), EPSILON); 1012 assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON); 1013 animatorSet.setCurrentPlayTime(699); 1014 assertEquals(699, animatorSet.getCurrentPlayTime()); 1015 assertEquals(99f / 300f, (float) animator2.getAnimatedValue(), EPSILON); 1016 animatorSet.setCurrentPlayTime(601); 1017 assertEquals(601, animatorSet.getCurrentPlayTime()); 1018 assertEquals(1f / 300f, (float) animator2.getAnimatedValue(), EPSILON); 1019 animatorSet.setCurrentPlayTime(599); 1020 assertEquals(599, animatorSet.getCurrentPlayTime()); 1021 assertEquals(299f / 300f, (float) animator1.getAnimatedValue(), EPSILON); 1022 assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON); 1023 } 1024 1025 @Test seekReverse()1026 public void seekReverse() throws Throwable { 1027 AnimatorSet animatorSet = new AnimatorSet(); 1028 animatorSet.setStartDelay(10); 1029 ValueAnimator animator1 = ValueAnimator.ofFloat(0f, 1f); 1030 animator1.setInterpolator(null); 1031 animator1.setStartDelay(5); 1032 ValueAnimator animator2 = ValueAnimator.ofFloat(0f, 1f); 1033 animator2.setInterpolator(null); 1034 animator2.setStartDelay(5); 1035 animatorSet.playSequentially(animator1, animator2); 1036 mActivityRule.runOnUiThread(() -> { 1037 animatorSet.reverse(); 1038 animatorSet.pause(); 1039 assertEquals(1f, (float) animator1.getAnimatedValue(), EPSILON); 1040 assertEquals(1f, (float) animator2.getAnimatedValue(), EPSILON); 1041 animatorSet.setCurrentPlayTime(1); 1042 assertEquals(1f, (float) animator1.getAnimatedValue(), EPSILON); 1043 assertEquals(299f / 300f, (float) animator2.getAnimatedValue(), EPSILON); 1044 animatorSet.setCurrentPlayTime(300); 1045 assertEquals(1f, (float) animator1.getAnimatedValue(), EPSILON); 1046 assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON); 1047 animatorSet.setCurrentPlayTime(305); 1048 assertEquals(1f, (float) animator1.getAnimatedValue(), EPSILON); 1049 assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON); 1050 animatorSet.setCurrentPlayTime(306); 1051 assertEquals(299f / 300f, (float) animator1.getAnimatedValue(), EPSILON); 1052 assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON); 1053 animatorSet.setCurrentPlayTime(604); 1054 assertEquals(1f / 300f, (float) animator1.getAnimatedValue(), EPSILON); 1055 assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON); 1056 animatorSet.setCurrentPlayTime(610); 1057 assertEquals(0f, (float) animator1.getAnimatedValue(), EPSILON); 1058 assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON); 1059 animatorSet.setCurrentPlayTime(604); 1060 assertEquals(1f / 300f, (float) animator1.getAnimatedValue(), EPSILON); 1061 assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON); 1062 animatorSet.setCurrentPlayTime(305); 1063 assertEquals(1f, (float) animator1.getAnimatedValue(), EPSILON); 1064 assertEquals(0f, (float) animator2.getAnimatedValue(), EPSILON); 1065 }); 1066 } 1067 1068 @Test seekForwardOrder()1069 public void seekForwardOrder() { 1070 TargetObj target = new TargetObj(); 1071 target.setVal(20f); 1072 ObjectAnimator animator1 = ObjectAnimator.ofFloat(target, "val", 0f, 100f); 1073 animator1.setInterpolator(null); 1074 ObjectAnimator animator2 = ObjectAnimator.ofFloat(target, "val", 100f, 0f); 1075 animator2.setInterpolator(null); 1076 AnimatorSet animatorSet = new AnimatorSet(); 1077 animatorSet.playSequentially(animator1, animator2); 1078 1079 animatorSet.setCurrentPlayTime(0); 1080 assertEquals(0f, target.value, EPSILON); 1081 1082 animatorSet.setCurrentPlayTime(200); 1083 assertEquals(100f * 200f / 300f, target.value, EPSILON); 1084 1085 animatorSet.setCurrentPlayTime(300); 1086 assertEquals(100f, target.value, EPSILON); 1087 1088 animatorSet.setCurrentPlayTime(350); 1089 assertEquals(100f * 250f / 300f, target.value, EPSILON); 1090 1091 animatorSet.setCurrentPlayTime(600); 1092 assertEquals(0f, target.value, EPSILON); 1093 1094 animatorSet.setCurrentPlayTime(250); 1095 assertEquals(100f * 250f / 300f, target.value, EPSILON); 1096 1097 animatorSet.setCurrentPlayTime(0); 1098 assertEquals(0f, target.value, EPSILON); 1099 } 1100 1101 @Test seekBackwardOrder()1102 public void seekBackwardOrder() throws Throwable { 1103 TargetObj target = new TargetObj(); 1104 target.setVal(20f); 1105 ObjectAnimator animator1 = ObjectAnimator.ofFloat(target, "val", 0f, 100f); 1106 animator1.setInterpolator(null); 1107 ObjectAnimator animator2 = ObjectAnimator.ofFloat(target, "val", 100f, 0f); 1108 animator2.setInterpolator(null); 1109 AnimatorSet animatorSet = new AnimatorSet(); 1110 animatorSet.playSequentially(animator1, animator2); 1111 1112 mActivityRule.runOnUiThread(() -> { 1113 animatorSet.reverse(); 1114 animatorSet.pause(); 1115 1116 animatorSet.setCurrentPlayTime(0); 1117 assertEquals(0f, target.value, EPSILON); 1118 1119 animatorSet.setCurrentPlayTime(200); 1120 assertEquals(100f * 200f / 300f, target.value, EPSILON); 1121 1122 animatorSet.setCurrentPlayTime(300); 1123 assertEquals(100f, target.value, EPSILON); 1124 1125 animatorSet.setCurrentPlayTime(350); 1126 assertEquals(100f * 250f / 300f, target.value, EPSILON); 1127 1128 animatorSet.setCurrentPlayTime(600); 1129 assertEquals(0f, target.value, EPSILON); 1130 1131 animatorSet.setCurrentPlayTime(250); 1132 assertEquals(100f * 250f / 300f, target.value, EPSILON); 1133 1134 animatorSet.setCurrentPlayTime(0); 1135 assertEquals(0f, target.value, EPSILON); 1136 }); 1137 } 1138 1139 @Test seekNestedSets()1140 public void seekNestedSets() { 1141 TargetObj target = new TargetObj(); 1142 target.setVal(20f); 1143 ObjectAnimator animator1 = ObjectAnimator.ofFloat(target, "val", 0f, 100f); 1144 animator1.setInterpolator(null); 1145 ObjectAnimator animator2 = ObjectAnimator.ofFloat(target, "val", 100f, 0f); 1146 animator2.setInterpolator(null); 1147 AnimatorSet animatorSet1 = new AnimatorSet(); 1148 animatorSet1.playSequentially(animator1, animator2); 1149 ValueAnimator animator3 = ValueAnimator.ofFloat(0f, 1f); 1150 animator3.setInterpolator(null); 1151 animator3.setStartDelay(100); 1152 AnimatorSet animatorSet = new AnimatorSet(); 1153 animatorSet.playTogether(animatorSet1, animator3); 1154 1155 animatorSet.setCurrentPlayTime(0); 1156 assertEquals(0f, target.value, EPSILON); 1157 assertEquals(0f, (float) animator3.getAnimatedValue(), EPSILON); 1158 1159 animatorSet.setCurrentPlayTime(200); 1160 assertEquals(100f * 200f / 300f, target.value, EPSILON); 1161 assertEquals(100f / 300f, (float) animator3.getAnimatedValue(), EPSILON); 1162 1163 animatorSet.setCurrentPlayTime(300); 1164 assertEquals(100f, target.value, EPSILON); 1165 assertEquals(200f / 300f, (float) animator3.getAnimatedValue(), EPSILON); 1166 1167 animatorSet.setCurrentPlayTime(350); 1168 assertEquals(100f * 250f / 300f, target.value, EPSILON); 1169 assertEquals(250f / 300f, (float) animator3.getAnimatedValue(), EPSILON); 1170 1171 animatorSet.setCurrentPlayTime(600); 1172 assertEquals(0f, target.value, EPSILON); 1173 assertEquals(1f, (float) animator3.getAnimatedValue(), EPSILON); 1174 1175 animatorSet.setCurrentPlayTime(250); 1176 assertEquals(100f * 250f / 300f, target.value, EPSILON); 1177 assertEquals(150f / 300f, (float) animator3.getAnimatedValue(), EPSILON); 1178 1179 animatorSet.setCurrentPlayTime(100); 1180 assertEquals(100f * 100f / 300f, target.value, EPSILON); 1181 assertEquals(0f, (float) animator3.getAnimatedValue(), EPSILON); 1182 1183 animatorSet.setCurrentPlayTime(0); 1184 assertEquals(0f, target.value, EPSILON); 1185 assertEquals(0f, (float) animator3.getAnimatedValue(), EPSILON); 1186 } 1187 1188 @Test seekWithNestedAnimatorSetsAndDelays()1189 public void seekWithNestedAnimatorSetsAndDelays() { 1190 AnimatorSet animatorSet1 = new AnimatorSet(); 1191 animatorSet1.setStartDelay(100); 1192 ValueAnimator animator1 = ValueAnimator.ofFloat(0f, 100f); 1193 animator1.setInterpolator(null); 1194 animator1.setStartDelay(200); 1195 animatorSet1.play(animator1); 1196 AnimatorSet animatorSet2 = new AnimatorSet(); 1197 animatorSet2.setStartDelay(400); 1198 animatorSet2.play(animatorSet1); 1199 AnimatorSet animatorSet3 = new AnimatorSet(); 1200 animatorSet3.play(animatorSet2); 1201 1202 animatorSet3.setCurrentPlayTime(0); 1203 assertEquals(0f, (float) animator1.getAnimatedValue(), EPSILON); 1204 animatorSet3.setCurrentPlayTime(400); 1205 assertEquals(0f, (float) animator1.getAnimatedValue(), EPSILON); 1206 animatorSet3.setCurrentPlayTime(500); 1207 assertEquals(0f, (float) animator1.getAnimatedValue(), EPSILON); 1208 animatorSet3.setCurrentPlayTime(700); 1209 assertEquals(0f, (float) animator1.getAnimatedValue(), EPSILON); 1210 animatorSet3.setCurrentPlayTime(850); 1211 assertEquals(50f, (float) animator1.getAnimatedValue(), EPSILON); 1212 animatorSet3.setCurrentPlayTime(1000); 1213 assertEquals(100f, (float) animator1.getAnimatedValue(), EPSILON); 1214 } 1215 1216 @Test seekReversedWithNestedAnimatorSetsAndDelays()1217 public void seekReversedWithNestedAnimatorSetsAndDelays() throws Throwable { 1218 AnimatorSet animatorSet1 = new AnimatorSet(); 1219 animatorSet1.setStartDelay(100); 1220 ValueAnimator animator1 = ValueAnimator.ofFloat(0f, 100f); 1221 animator1.setInterpolator(null); 1222 animator1.setStartDelay(200); 1223 animatorSet1.play(animator1); 1224 AnimatorSet animatorSet2 = new AnimatorSet(); 1225 animatorSet2.setStartDelay(400); 1226 animatorSet2.play(animatorSet1); 1227 AnimatorSet animatorSet3 = new AnimatorSet(); 1228 animatorSet3.play(animatorSet2); 1229 1230 mActivityRule.runOnUiThread(() -> { 1231 animatorSet3.reverse(); 1232 animatorSet3.pause(); 1233 animatorSet3.setCurrentPlayTime(0); 1234 assertEquals(100f, (float) animator1.getAnimatedValue(), EPSILON); 1235 animatorSet3.setCurrentPlayTime(150); 1236 assertEquals(50f, (float) animator1.getAnimatedValue(), EPSILON); 1237 animatorSet3.setCurrentPlayTime(300); 1238 assertEquals(0f, (float) animator1.getAnimatedValue(), EPSILON); 1239 animatorSet3.setCurrentPlayTime(500); 1240 assertEquals(0f, (float) animator1.getAnimatedValue(), EPSILON); 1241 animatorSet3.setCurrentPlayTime(600); 1242 assertEquals(0f, (float) animator1.getAnimatedValue(), EPSILON); 1243 animatorSet3.setCurrentPlayTime(1000); 1244 assertEquals(0f, (float) animator1.getAnimatedValue(), EPSILON); 1245 }); 1246 } 1247 1248 /** 1249 * This test sets up an AnimatorSet that contains two sequential animations. The first animation 1250 * is infinite, the second animation therefore has an infinite start time. This test verifies 1251 * that the infinite start time is handled correctly. 1252 */ 1253 @Test testInfiniteStartTime()1254 public void testInfiniteStartTime() throws Throwable { 1255 ValueAnimator a1 = ValueAnimator.ofFloat(0f, 1f); 1256 a1.setRepeatCount(ValueAnimator.INFINITE); 1257 ValueAnimator a2 = ValueAnimator.ofFloat(0f, 1f); 1258 1259 AnimatorSet set = new AnimatorSet(); 1260 set.playSequentially(a1, a2); 1261 1262 mActivityRule.runOnUiThread(() -> { 1263 set.start(); 1264 }); 1265 1266 assertEquals(Animator.DURATION_INFINITE, set.getTotalDuration()); 1267 1268 mActivityRule.runOnUiThread(() -> { 1269 set.end(); 1270 }); 1271 } 1272 1273 @Test childListenersCalledWhilePaused()1274 public void childListenersCalledWhilePaused() throws Throwable { 1275 AnimationCountListener setListener1 = new AnimationCountListener(); 1276 AnimationCountListener setListener2 = new AnimationCountListener(); 1277 AnimatorSet animatorSet1 = new AnimatorSet(); 1278 animatorSet1.addListener(setListener1); 1279 AnimatorSet animatorSet2 = new AnimatorSet(); 1280 animatorSet2.addListener(setListener2); 1281 animatorSet2.setStartDelay(100); 1282 animatorSet1.play(animatorSet2); 1283 1284 AnimatorSet animatorSet3 = new AnimatorSet(); 1285 animatorSet2.play(animatorSet3); 1286 AnimationCountListener setListener3 = new AnimationCountListener(); 1287 animatorSet3.addListener(setListener3); 1288 1289 AnimationCountListener valueListener = new AnimationCountListener(); 1290 ValueAnimator animator = ValueAnimator.ofFloat(0f, 100f); 1291 animator.addListener(valueListener); 1292 animator.setStartDelay(50); 1293 animatorSet3.play(animator); 1294 1295 mActivityRule.runOnUiThread(() -> { 1296 animatorSet1.start(); 1297 // Just starting should trigger the starting animators 1298 setListener1.assertListenerCount(1, 0, 0, 0); 1299 setListener2.assertListenerCount(1, 0, 0, 0); 1300 setListener3.assertListenerCount(0, 0, 0, 0); 1301 valueListener.assertListenerCount(0, 0, 0, 0); 1302 1303 animatorSet1.pause(); 1304 1305 // Setting the play time shouldn't trigger any more animators 1306 animatorSet1.setCurrentPlayTime(0); 1307 setListener1.assertListenerCount(1, 0, 0, 0); 1308 setListener2.assertListenerCount(1, 0, 0, 0); 1309 setListener3.assertListenerCount(0, 0, 0, 0); 1310 valueListener.assertListenerCount(0, 0, 0, 0); 1311 1312 // We've passed the start delay, so other animators should start 1313 animatorSet1.setCurrentPlayTime(100); 1314 setListener1.assertListenerCount(1, 0, 0, 0); 1315 setListener2.assertListenerCount(1, 0, 0, 0); 1316 setListener3.assertListenerCount(1, 0, 0, 0); 1317 valueListener.assertListenerCount(1, 0, 0, 0); 1318 1319 // Reached the end of the animators, so all should end in the forward direction. 1320 animatorSet1.setCurrentPlayTime(450); 1321 setListener1.assertListenerCount(1, 0, 1, 0); 1322 setListener2.assertListenerCount(1, 0, 1, 0); 1323 setListener3.assertListenerCount(1, 0, 1, 0); 1324 valueListener.assertListenerCount(1, 0, 1, 0); 1325 1326 // Go back towards the start should cause the animators to start in reverse 1327 animatorSet1.setCurrentPlayTime(101); 1328 setListener1.assertListenerCount(1, 1, 1, 0); 1329 setListener2.assertListenerCount(1, 1, 1, 0); 1330 setListener3.assertListenerCount(1, 1, 1, 0); 1331 valueListener.assertListenerCount(1, 1, 1, 0); 1332 1333 // Now we've reached the start delay, so some animators finish 1334 animatorSet1.setCurrentPlayTime(100); 1335 setListener1.assertListenerCount(1, 1, 1, 0); 1336 setListener2.assertListenerCount(1, 1, 1, 0); 1337 setListener3.assertListenerCount(1, 1, 1, 1); 1338 valueListener.assertListenerCount(1, 1, 1, 1); 1339 1340 // Now we're back at the beginning, so all animators will finish in reverse 1341 animatorSet1.setCurrentPlayTime(0); 1342 setListener1.assertListenerCount(1, 1, 1, 1); 1343 setListener2.assertListenerCount(1, 1, 1, 1); 1344 setListener3.assertListenerCount(1, 1, 1, 1); 1345 valueListener.assertListenerCount(1, 1, 1, 1); 1346 1347 // Go forward to the middle, we'll have another start in the forward direction 1348 animatorSet1.setCurrentPlayTime(300); 1349 setListener1.assertListenerCount(2, 1, 1, 1); 1350 setListener2.assertListenerCount(2, 1, 1, 1); 1351 setListener3.assertListenerCount(2, 1, 1, 1); 1352 valueListener.assertListenerCount(2, 1, 1, 1); 1353 1354 // When we go back, it should end in the reverse direction 1355 animatorSet1.setCurrentPlayTime(0); 1356 setListener1.assertListenerCount(2, 1, 1, 2); 1357 setListener2.assertListenerCount(2, 1, 1, 2); 1358 setListener3.assertListenerCount(2, 1, 1, 2); 1359 valueListener.assertListenerCount(2, 1, 1, 2); 1360 }); 1361 } 1362 1363 @Test childListenersCalledReversed()1364 public void childListenersCalledReversed() throws Throwable { 1365 AnimationCountListener setListener = new AnimationCountListener(); 1366 AnimatorSet animatorSet = new AnimatorSet(); 1367 animatorSet.addListener(setListener); 1368 1369 AnimationCountListener valueListener = new AnimationCountListener(); 1370 ValueAnimator animator = ValueAnimator.ofFloat(0f, 100f); 1371 animator.addListener(valueListener); 1372 animator.setRepeatCount(1); 1373 animator.setStartDelay(50); 1374 animatorSet.play(animator); 1375 1376 mActivityRule.runOnUiThread(() -> { 1377 animatorSet.reverse(); 1378 // Just starting should trigger the starting animators 1379 setListener.assertListenerCount(0, 1, 0, 0); 1380 valueListener.assertListenerCount(0, 1, 0, 0); 1381 1382 // Setting the play time shouldn't trigger any more animators 1383 animatorSet.setCurrentPlayTime(0); 1384 setListener.assertListenerCount(0, 1, 0, 0); 1385 valueListener.assertListenerCount(0, 1, 0, 0); 1386 1387 // Middle of the ValueAnimator 1388 animatorSet.setCurrentPlayTime(300); 1389 setListener.assertListenerCount(0, 1, 0, 0); 1390 valueListener.assertListenerCount(0, 1, 0, 0); 1391 1392 // Reached the end of the ValueAnimator, but not the start delay 1393 animatorSet.setCurrentPlayTime(600); 1394 setListener.assertListenerCount(0, 1, 0, 0); 1395 valueListener.assertListenerCount(0, 1, 0, 0); 1396 1397 // End of the startDelay 1398 animatorSet.setCurrentPlayTime(650); 1399 setListener.assertListenerCount(0, 1, 0, 1); 1400 valueListener.assertListenerCount(0, 1, 0, 1); 1401 }); 1402 } 1403 1404 @Test childListenersCalledWithNoStart()1405 public void childListenersCalledWithNoStart() { 1406 AnimationCountListener setListener1 = new AnimationCountListener(); 1407 AnimationCountListener setListener2 = new AnimationCountListener(); 1408 AnimatorSet animatorSet1 = new AnimatorSet(); 1409 animatorSet1.addListener(setListener1); 1410 AnimatorSet animatorSet2 = new AnimatorSet(); 1411 animatorSet2.addListener(setListener2); 1412 animatorSet2.setStartDelay(100); 1413 animatorSet1.play(animatorSet2); 1414 1415 AnimatorSet animatorSet3 = new AnimatorSet(); 1416 animatorSet2.play(animatorSet3); 1417 AnimationCountListener setListener3 = new AnimationCountListener(); 1418 animatorSet3.addListener(setListener3); 1419 1420 AnimationCountListener valueListener = new AnimationCountListener(); 1421 ValueAnimator animator = ValueAnimator.ofFloat(0f, 100f); 1422 animator.addListener(valueListener); 1423 animator.setStartDelay(50); 1424 animatorSet3.play(animator); 1425 1426 // Nothing is started, so no listeners should be called 1427 setListener1.assertListenerCount(0, 0, 0, 0); 1428 setListener2.assertListenerCount(0, 0, 0, 0); 1429 setListener3.assertListenerCount(0, 0, 0, 0); 1430 valueListener.assertListenerCount(0, 0, 0, 0); 1431 1432 // Just setting the play time should start some listeners 1433 animatorSet1.setCurrentPlayTime(0); 1434 1435 setListener1.assertListenerCount(1, 0, 0, 0); 1436 setListener2.assertListenerCount(1, 0, 0, 0); 1437 setListener3.assertListenerCount(0, 0, 0, 0); 1438 valueListener.assertListenerCount(0, 0, 0, 0); 1439 1440 // We've passed the start delay, so other animators should start 1441 animatorSet1.setCurrentPlayTime(100); 1442 setListener1.assertListenerCount(1, 0, 0, 0); 1443 setListener2.assertListenerCount(1, 0, 0, 0); 1444 setListener3.assertListenerCount(1, 0, 0, 0); 1445 valueListener.assertListenerCount(1, 0, 0, 0); 1446 1447 // Reached the end of the animators, so all should end in the forward direction. 1448 animatorSet1.setCurrentPlayTime(450); 1449 setListener1.assertListenerCount(1, 0, 1, 0); 1450 setListener2.assertListenerCount(1, 0, 1, 0); 1451 setListener3.assertListenerCount(1, 0, 1, 0); 1452 valueListener.assertListenerCount(1, 0, 1, 0); 1453 1454 // Go back towards the start should cause the animators to start in reverse 1455 animatorSet1.setCurrentPlayTime(101); 1456 setListener1.assertListenerCount(1, 1, 1, 0); 1457 setListener2.assertListenerCount(1, 1, 1, 0); 1458 setListener3.assertListenerCount(1, 1, 1, 0); 1459 valueListener.assertListenerCount(1, 1, 1, 0); 1460 1461 // Now we've reached the start delay, so some animators finish 1462 animatorSet1.setCurrentPlayTime(100); 1463 setListener1.assertListenerCount(1, 1, 1, 0); 1464 setListener2.assertListenerCount(1, 1, 1, 0); 1465 setListener3.assertListenerCount(1, 1, 1, 1); 1466 valueListener.assertListenerCount(1, 1, 1, 1); 1467 1468 // Now we're back at the beginning, so all animators will finish in reverse 1469 animatorSet1.setCurrentPlayTime(0); 1470 setListener1.assertListenerCount(1, 1, 1, 1); 1471 setListener2.assertListenerCount(1, 1, 1, 1); 1472 setListener3.assertListenerCount(1, 1, 1, 1); 1473 valueListener.assertListenerCount(1, 1, 1, 1); 1474 1475 // Go forward to the middle, we'll have another start in the forward direction 1476 animatorSet1.setCurrentPlayTime(300); 1477 setListener1.assertListenerCount(2, 1, 1, 1); 1478 setListener2.assertListenerCount(2, 1, 1, 1); 1479 setListener3.assertListenerCount(2, 1, 1, 1); 1480 valueListener.assertListenerCount(2, 1, 1, 1); 1481 1482 // When we go back, it should end in the reverse direction 1483 animatorSet1.setCurrentPlayTime(0); 1484 setListener1.assertListenerCount(2, 1, 1, 2); 1485 setListener2.assertListenerCount(2, 1, 1, 2); 1486 setListener3.assertListenerCount(2, 1, 1, 2); 1487 valueListener.assertListenerCount(2, 1, 1, 2); 1488 } 1489 1490 static class AnimationCountListener implements Animator.AnimatorListener { 1491 public int startForward; 1492 public int startReversed; 1493 public int endForward; 1494 public int endReversed; 1495 1496 @Override onAnimationStart(@onNull Animator animation, boolean isReverse)1497 public void onAnimationStart(@NonNull Animator animation, boolean isReverse) { 1498 if (isReverse) { 1499 startReversed++; 1500 } else { 1501 startForward++; 1502 } 1503 } 1504 1505 @Override onAnimationEnd(@onNull Animator animation, boolean isReverse)1506 public void onAnimationEnd(@NonNull Animator animation, boolean isReverse) { 1507 if (isReverse) { 1508 endReversed++; 1509 } else { 1510 endForward++; 1511 } 1512 } 1513 1514 @Override onAnimationStart(@onNull Animator animation)1515 public void onAnimationStart(@NonNull Animator animation) { 1516 } 1517 1518 @Override onAnimationEnd(@onNull Animator animation)1519 public void onAnimationEnd(@NonNull Animator animation) { 1520 } 1521 1522 @Override onAnimationCancel(@onNull Animator animation)1523 public void onAnimationCancel(@NonNull Animator animation) { 1524 } 1525 1526 @Override onAnimationRepeat(@onNull Animator animation)1527 public void onAnimationRepeat(@NonNull Animator animation) { 1528 } 1529 assertListenerCount( int startForward, int startReversed, int endForward, int endReversed )1530 public void assertListenerCount( 1531 int startForward, 1532 int startReversed, 1533 int endForward, 1534 int endReversed 1535 ) { 1536 assertEquals(startForward, this.startForward); 1537 assertEquals(startReversed, this.startReversed); 1538 assertEquals(endForward, this.endForward); 1539 assertEquals(endReversed, this.endReversed); 1540 } 1541 } 1542 1543 static class TargetObj { 1544 public float value = 0; 1545 setVal(float value)1546 public void setVal(float value) { 1547 this.value = value; 1548 } 1549 getVal()1550 public float getVal() { 1551 return value; 1552 } 1553 } 1554 1555 class AnimateObject { 1556 int x = 1; 1557 int y = 2; 1558 } 1559 1560 static class MyListener extends AnimatorListenerAdapter { 1561 boolean mStartIsCalled = false; 1562 boolean mEndIsCalled = false; 1563 onAnimationStart(Animator animation)1564 public void onAnimationStart(Animator animation) { 1565 mStartIsCalled = true; 1566 } 1567 onAnimationEnd(Animator animation)1568 public void onAnimationEnd(Animator animation) { 1569 mEndIsCalled = true; 1570 } 1571 } 1572 1573 static class MyValueAnimator extends ValueAnimator { 1574 boolean mStartCalled = false; 1575 @Override start()1576 public void start() { 1577 // Do not call super intentionally. 1578 mStartCalled = true; 1579 } 1580 } 1581 } 1582