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