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.test.InstrumentationRegistry; 44 import androidx.test.filters.MediumTest; 45 import androidx.test.rule.ActivityTestRule; 46 import androidx.test.runner.AndroidJUnit4; 47 48 import org.junit.After; 49 import org.junit.Before; 50 import org.junit.Rule; 51 import org.junit.Test; 52 import org.junit.runner.RunWith; 53 54 import java.util.ArrayList; 55 import java.util.HashSet; 56 import java.util.List; 57 import java.util.Set; 58 import java.util.concurrent.CountDownLatch; 59 import java.util.concurrent.TimeUnit; 60 61 @MediumTest 62 @RunWith(AndroidJUnit4.class) 63 public class AnimatorSetTest { 64 private AnimationActivity mActivity; 65 private AnimatorSet mAnimatorSet; 66 private float mPreviousDurationScale = 1.0f; 67 private long mDuration = 1000; 68 private Object object; 69 private ObjectAnimator yAnimator; 70 private ObjectAnimator xAnimator; 71 Set<Integer> identityHashes = new HashSet<>(); 72 private static final float EPSILON = 0.001f; 73 74 @Rule 75 public ActivityTestRule<AnimationActivity> mActivityRule = 76 new ActivityTestRule<>(AnimationActivity.class); 77 78 @Before setup()79 public void setup() { 80 InstrumentationRegistry.getInstrumentation().setInTouchMode(false); 81 mActivity = mActivityRule.getActivity(); 82 mPreviousDurationScale = ValueAnimator.getDurationScale(); 83 ValueAnimator.setDurationScale(1.0f); 84 object = mActivity.view.newBall; 85 yAnimator = getYAnimator(object); 86 xAnimator = getXAnimator(object); 87 } 88 89 @After tearDown()90 public void tearDown() { 91 ValueAnimator.setDurationScale(mPreviousDurationScale); 92 } 93 94 @Test testPlaySequentially()95 public void testPlaySequentially() throws Throwable { 96 xAnimator.setRepeatCount(0); 97 yAnimator.setRepeatCount(0); 98 xAnimator.setDuration(50); 99 yAnimator.setDuration(50); 100 List<Animator> animators = new ArrayList<Animator>(); 101 animators.add(xAnimator); 102 animators.add(yAnimator); 103 mAnimatorSet = new AnimatorSet(); 104 mAnimatorSet.playSequentially(animators); 105 verifySequentialPlayOrder(mAnimatorSet, new Animator[] {xAnimator, yAnimator}); 106 107 ValueAnimator anim1 = ValueAnimator.ofFloat(0f, 1f); 108 ValueAnimator anim2 = ValueAnimator.ofInt(0, 100); 109 anim1.setDuration(50); 110 anim2.setDuration(50); 111 AnimatorSet set = new AnimatorSet(); 112 set.playSequentially(anim1, anim2); 113 verifySequentialPlayOrder(set, new Animator[] {anim1, anim2}); 114 } 115 116 /** 117 * Start the animator, and verify the animators are played sequentially in the order that is 118 * defined in the array. 119 * 120 * @param set AnimatorSet to be started and verified 121 * @param animators animators that we put in the AnimatorSet, in the order that they'll play 122 */ verifySequentialPlayOrder(final AnimatorSet set, Animator[] animators)123 private void verifySequentialPlayOrder(final AnimatorSet set, Animator[] animators) 124 throws Throwable { 125 126 final MyListener[] listeners = new MyListener[animators.length]; 127 for (int i = 0; i < animators.length; i++) { 128 if (i == 0) { 129 listeners[i] = new MyListener(); 130 } else { 131 final int current = i; 132 listeners[i] = new MyListener() { 133 @Override 134 public void onAnimationStart(Animator anim) { 135 super.onAnimationStart(anim); 136 // Check that the previous animator has finished. 137 assertTrue(listeners[current - 1].mEndIsCalled); 138 } 139 }; 140 } 141 animators[i].addListener(listeners[i]); 142 } 143 144 final CountDownLatch startLatch = new CountDownLatch(1); 145 final CountDownLatch endLatch = new CountDownLatch(1); 146 147 set.addListener(new MyListener() { 148 @Override 149 public void onAnimationEnd(Animator anim) { 150 endLatch.countDown(); 151 } 152 }); 153 154 long totalDuration = set.getTotalDuration(); 155 assertFalse(set.isRunning()); 156 mActivityRule.runOnUiThread(() -> { 157 set.start(); 158 startLatch.countDown(); 159 }); 160 161 // Set timeout to 100ms, if current count reaches 0 before the timeout, startLatch.await(...) 162 // will return immediately. 163 assertTrue(startLatch.await(100, TimeUnit.MILLISECONDS)); 164 assertTrue(set.isRunning()); 165 assertTrue(endLatch.await(totalDuration * 2, TimeUnit.MILLISECONDS)); 166 // Check that all the animators have finished. 167 for (int i = 0; i < listeners.length; i++) { 168 assertTrue(listeners[i].mEndIsCalled); 169 } 170 171 // Now reverse the animations and verify whether the play order is reversed. 172 for (int i = 0; i < animators.length; i++) { 173 if (i == animators.length - 1) { 174 listeners[i] = new MyListener(); 175 } else { 176 final int current = i; 177 listeners[i] = new MyListener() { 178 @Override 179 public void onAnimationStart(Animator anim) { 180 super.onAnimationStart(anim); 181 // Check that the previous animator has finished. 182 assertTrue(listeners[current + 1].mEndIsCalled); 183 } 184 }; 185 } 186 animators[i].removeAllListeners(); 187 animators[i].addListener(listeners[i]); 188 } 189 190 mActivityRule.runOnUiThread(() -> { 191 set.reverse(); 192 startLatch.countDown(); 193 }); 194 195 // Set timeout to 100ms, if current count reaches 0 before the timeout, startLatch.await(..) 196 // will return immediately. 197 assertTrue(startLatch.await(100, TimeUnit.MILLISECONDS)); 198 assertTrue(set.isRunning()); 199 assertTrue(endLatch.await(totalDuration * 2, TimeUnit.MILLISECONDS)); 200 201 } 202 203 @Test testPlayTogether()204 public void testPlayTogether() throws Throwable { 205 xAnimator.setRepeatCount(ValueAnimator.INFINITE); 206 Animator[] animatorArray = {xAnimator, yAnimator}; 207 208 mAnimatorSet = new AnimatorSet(); 209 mAnimatorSet.playTogether(animatorArray); 210 211 assertFalse(mAnimatorSet.isRunning()); 212 assertFalse(xAnimator.isRunning()); 213 assertFalse(yAnimator.isRunning()); 214 startAnimation(mAnimatorSet); 215 SystemClock.sleep(100); 216 assertTrue(mAnimatorSet.isRunning()); 217 assertTrue(xAnimator.isRunning()); 218 assertTrue(yAnimator.isRunning()); 219 220 // Now assemble another animator set 221 ValueAnimator anim1 = ValueAnimator.ofFloat(0f, 100f); 222 ValueAnimator anim2 = ValueAnimator.ofFloat(10f, 100f); 223 AnimatorSet set = new AnimatorSet(); 224 set.playTogether(anim1, anim2); 225 226 assertFalse(set.isRunning()); 227 assertFalse(anim1.isRunning()); 228 assertFalse(anim2.isRunning()); 229 startAnimation(set); 230 SystemClock.sleep(100); 231 assertTrue(set.isRunning()); 232 assertTrue(anim1.isRunning()); 233 assertTrue(anim2.isRunning()); 234 } 235 236 @Test testPlayBeforeAfter()237 public void testPlayBeforeAfter() throws Throwable { 238 xAnimator.setRepeatCount(0); 239 yAnimator.setRepeatCount(0); 240 final ValueAnimator zAnimator = ValueAnimator.ofFloat(0f, 100f); 241 242 xAnimator.setDuration(50); 243 yAnimator.setDuration(50); 244 zAnimator.setDuration(50); 245 246 AnimatorSet set = new AnimatorSet(); 247 set.play(yAnimator).before(zAnimator).after(xAnimator); 248 249 verifySequentialPlayOrder(set, new Animator[] {xAnimator, yAnimator, zAnimator}); 250 } 251 252 @Test testListenerCallbackOnEmptySet()253 public void testListenerCallbackOnEmptySet() throws Throwable { 254 // Create an AnimatorSet that only contains one empty AnimatorSet, and checks the callback 255 // sequence by checking the time stamps of the callbacks. 256 final AnimatorSet emptySet = new AnimatorSet(); 257 final AnimatorSet set = new AnimatorSet(); 258 set.play(emptySet); 259 MyListener listener = new MyListener() { 260 long startTime = 0; 261 long endTime = 0; 262 @Override 263 public void onAnimationStart(Animator animation) { 264 super.onAnimationStart(animation); 265 startTime = SystemClock.currentThreadTimeMillis(); 266 } 267 268 @Override 269 public void onAnimationEnd(Animator animation) { 270 super.onAnimationEnd(animation); 271 endTime = SystemClock.currentThreadTimeMillis(); 272 assertTrue(endTime >= startTime); 273 assertTrue(startTime != 0); 274 } 275 }; 276 set.addListener(listener); 277 mActivityRule.runOnUiThread(() -> { 278 set.start(); 279 }); 280 assertTrue(listener.mStartIsCalled); 281 assertTrue(listener.mEndIsCalled); 282 } 283 284 @Test testPauseAndResume()285 public void testPauseAndResume() throws Throwable { 286 final AnimatorSet set = new AnimatorSet(); 287 ValueAnimator a1 = ValueAnimator.ofFloat(0f, 100f); 288 a1.setDuration(50); 289 ValueAnimator a2 = ValueAnimator.ofFloat(0f, 100f); 290 a2.setDuration(50); 291 a1.addListener(new AnimatorListenerAdapter() { 292 @Override 293 public void onAnimationStart(Animator animation) { 294 // Pause non-delayed set once the child animator starts 295 set.pause(); 296 } 297 }); 298 set.playTogether(a1, a2); 299 300 final AnimatorSet delayedSet = new AnimatorSet(); 301 ValueAnimator a3 = ValueAnimator.ofFloat(0f, 100f); 302 a3.setDuration(50); 303 ValueAnimator a4 = ValueAnimator.ofFloat(0f, 100f); 304 a4.setDuration(50); 305 delayedSet.playSequentially(a3, a4); 306 delayedSet.setStartDelay(50); 307 308 MyListener l1 = new MyListener(); 309 MyListener l2 = new MyListener(); 310 set.addListener(l1); 311 delayedSet.addListener(l2); 312 313 mActivityRule.runOnUiThread(() -> { 314 set.start(); 315 delayedSet.start(); 316 317 // Pause the delayed set during start delay 318 delayedSet.pause(); 319 }); 320 321 // Sleep long enough so that if the sets are not properly paused, they would have 322 // finished. 323 SystemClock.sleep(300); 324 // Verify that both sets have been paused and *not* finished. 325 assertTrue(set.isPaused()); 326 assertTrue(delayedSet.isPaused()); 327 assertTrue(l1.mStartIsCalled); 328 assertTrue(l2.mStartIsCalled); 329 assertFalse(l1.mEndIsCalled); 330 assertFalse(l2.mEndIsCalled); 331 332 mActivityRule.runOnUiThread(() -> { 333 set.resume(); 334 delayedSet.resume(); 335 }); 336 SystemClock.sleep(300); 337 338 assertFalse(set.isPaused()); 339 assertFalse(delayedSet.isPaused()); 340 assertTrue(l1.mEndIsCalled); 341 assertTrue(l2.mEndIsCalled); 342 } 343 344 @Test testPauseBeforeStart()345 public void testPauseBeforeStart() throws Throwable { 346 final AnimatorSet set = new AnimatorSet(); 347 ValueAnimator a1 = ValueAnimator.ofFloat(0f, 100f); 348 a1.setDuration(50); 349 ValueAnimator a2 = ValueAnimator.ofFloat(0f, 100f); 350 a2.setDuration(50); 351 set.setStartDelay(50); 352 set.playSequentially(a1, a2); 353 354 final MyListener listener = new MyListener(); 355 set.addListener(listener); 356 357 mActivityRule.runOnUiThread(() -> { 358 // Pause animator set before calling start() 359 set.pause(); 360 // Verify that pause should have no effect on a not-yet-started animator. 361 assertFalse(set.isPaused()); 362 set.start(); 363 }); 364 SystemClock.sleep(300); 365 366 // Animator set should finish running by now since it's not paused. 367 assertTrue(listener.mStartIsCalled); 368 assertTrue(listener.mEndIsCalled); 369 } 370 371 @Test testSeekAfterPause()372 public void testSeekAfterPause() throws Throwable { 373 final AnimatorSet set = new AnimatorSet(); 374 ValueAnimator a1 = ValueAnimator.ofFloat(0f, 50f); 375 a1.setDuration(50); 376 ValueAnimator a2 = ValueAnimator.ofFloat(50, 100f); 377 a2.setDuration(50); 378 set.playSequentially(a1, a2); 379 set.setInterpolator(new LinearInterpolator()); 380 381 mActivityRule.runOnUiThread(() -> { 382 set.start(); 383 set.pause(); 384 set.setCurrentPlayTime(60); 385 assertEquals((long) set.getCurrentPlayTime(), 60); 386 assertEquals((float) a1.getAnimatedValue(), 50f, EPSILON); 387 assertEquals((float) a2.getAnimatedValue(), 60f, EPSILON); 388 389 set.setCurrentPlayTime(40); 390 assertEquals((long) set.getCurrentPlayTime(), 40); 391 assertEquals((float) a1.getAnimatedValue(), 40f, EPSILON); 392 assertEquals((float) a2.getAnimatedValue(), 50f, EPSILON); 393 394 set.cancel(); 395 }); 396 } 397 398 @Test testDuration()399 public void testDuration() throws Throwable { 400 xAnimator.setRepeatCount(ValueAnimator.INFINITE); 401 Animator[] animatorArray = { xAnimator, yAnimator }; 402 403 mAnimatorSet = new AnimatorSet(); 404 mAnimatorSet.playTogether(animatorArray); 405 mAnimatorSet.setDuration(1000); 406 407 startAnimation(mAnimatorSet); 408 SystemClock.sleep(100); 409 assertEquals(mAnimatorSet.getDuration(), 1000); 410 } 411 412 @Test testStartDelay()413 public void testStartDelay() throws Throwable { 414 xAnimator.setRepeatCount(ValueAnimator.INFINITE); 415 Animator[] animatorArray = { xAnimator, yAnimator }; 416 417 mAnimatorSet = new AnimatorSet(); 418 mAnimatorSet.playTogether(animatorArray); 419 mAnimatorSet.setStartDelay(10); 420 421 startAnimation(mAnimatorSet); 422 SystemClock.sleep(100); 423 assertEquals(mAnimatorSet.getStartDelay(), 10); 424 } 425 426 /** 427 * This test sets up an AnimatorSet with start delay. One of the child animators also has 428 * start delay. We then verify that start delay was handled correctly on both AnimatorSet 429 * and individual animator level. 430 */ 431 @Test testReverseWithStartDelay()432 public void testReverseWithStartDelay() throws Throwable { 433 ValueAnimator a1 = ValueAnimator.ofFloat(0f, 1f); 434 a1.setDuration(200); 435 Animator.AnimatorListener listener1 = mock(AnimatorListenerAdapter.class); 436 a1.addListener(listener1); 437 438 ValueAnimator a2 = ValueAnimator.ofFloat(1f, 2f); 439 a2.setDuration(200); 440 // Set start delay on a2 so that the delay is passed 100ms after a1 is finished. 441 a2.setStartDelay(300); 442 Animator.AnimatorListener listener = mock(AnimatorListenerAdapter.class); 443 a2.addListener(listener); 444 445 a2.addListener(new AnimatorListenerAdapter() { 446 @Override 447 public void onAnimationEnd(Animator animation, boolean inReverse) { 448 assertTrue(inReverse); 449 // By the time a2 finishes reversing, a1 should not have started. 450 assertFalse(a1.isStarted()); 451 } 452 }); 453 454 AnimatorSet set = new AnimatorSet(); 455 set.playTogether(a1, a2); 456 set.setStartDelay(1000); 457 Animator.AnimatorListener setListener = mock(AnimatorListenerAdapter.class); 458 set.addListener(setListener); 459 mActivityRule.runOnUiThread(() -> { 460 set.reverse(); 461 assertTrue(a2.isStarted()); 462 assertTrue(a2.isRunning()); 463 }); 464 465 // a2 should finish 200ms after reverse started 466 verify(listener, within(300)).onAnimationEnd(a2, true); 467 // When a2 finishes, a1 should not have started yet 468 verify(listener1, never()).onAnimationStart(a1, true); 469 470 // The whole set should finish within 500ms, i.e. 300ms after a2 is finished. This verifies 471 // that the AnimatorSet didn't mistakenly use its start delay in the reverse run. 472 verify(setListener, within(400)).onAnimationEnd(set, true); 473 verify(listener1, times(1)).onAnimationEnd(a1, true); 474 475 } 476 477 /** 478 * Test that duration scale is handled correctly in the AnimatorSet. 479 */ 480 @Test testZeroDurationScale()481 public void testZeroDurationScale() throws Throwable { 482 ValueAnimator.setDurationScale(0); 483 484 ValueAnimator a1 = ValueAnimator.ofFloat(0f, 1f); 485 a1.setDuration(200); 486 Animator.AnimatorListener listener1 = mock(AnimatorListenerAdapter.class); 487 a1.addListener(listener1); 488 489 ValueAnimator a2 = ValueAnimator.ofFloat(1f, 2f); 490 a2.setDuration(200); 491 // Set start delay on a2 so that the delay is passed 100ms after a1 is finished. 492 a2.setStartDelay(300); 493 Animator.AnimatorListener listener2 = mock(AnimatorListenerAdapter.class); 494 a2.addListener(listener2); 495 496 AnimatorSet set = new AnimatorSet(); 497 set.playSequentially(a1, a2); 498 set.setStartDelay(1000); 499 Animator.AnimatorListener setListener = mock(AnimatorListenerAdapter.class); 500 set.addListener(setListener); 501 502 mActivityRule.runOnUiThread(() -> { 503 set.start(); 504 verify(setListener, times(0)).onAnimationEnd(any(AnimatorSet.class), 505 any(boolean.class)); 506 }); 507 verify(setListener, within(100)).onAnimationEnd(set, false); 508 verify(listener1, times(1)).onAnimationEnd(a1, false); 509 verify(listener2, times(1)).onAnimationEnd(a2, false); 510 } 511 512 /** 513 * Test that non-zero duration scale is handled correctly in the AnimatorSet. 514 */ 515 @Test testDurationScale()516 public void testDurationScale() throws Throwable { 517 // Change the duration scale to 3 518 ValueAnimator.setDurationScale(3f); 519 520 ValueAnimator a1 = ValueAnimator.ofFloat(0f, 1f); 521 a1.setDuration(100); 522 Animator.AnimatorListener listener1 = mock(AnimatorListenerAdapter.class); 523 a1.addListener(listener1); 524 525 ValueAnimator a2 = ValueAnimator.ofFloat(1f, 2f); 526 a2.setDuration(100); 527 // Set start delay on a2 so that the delay is passed 100ms after a1 is finished. 528 a2.setStartDelay(200); 529 Animator.AnimatorListener listener2 = mock(AnimatorListenerAdapter.class); 530 a2.addListener(listener2); 531 532 AnimatorSet set = new AnimatorSet(); 533 set.playSequentially(a1, a2); 534 Animator.AnimatorListener setListener = mock(AnimatorListenerAdapter.class); 535 set.addListener(setListener); 536 set.setStartDelay(200); 537 538 mActivityRule.runOnUiThread(() -> { 539 set.start(); 540 }); 541 542 // Sleep for part of the start delay and check that no child animator has started, to verify 543 // that the duration scale has been properly scaled. 544 SystemClock.sleep(400); 545 // start delay of the set should be scaled to 600ms 546 verify(listener1, never()).onAnimationStart(a1, false); 547 verify(listener2, never()).onAnimationStart(a2, false); 548 549 verify(listener1, within(400)).onAnimationStart(a1, false); 550 // Verify that a1 finish in ~300ms (3x its defined duration) 551 verify(listener1, within(500)).onAnimationEnd(a1, false); 552 553 // a2 should be in the delayed stage after a1 is finished 554 assertTrue(a2.isStarted()); 555 assertFalse(a2.isRunning()); 556 557 verify(listener2, within(800)).onAnimationStart(a2, false); 558 assertTrue(a2.isRunning()); 559 560 // Verify that the AnimatorSet has finished within 1650ms since the start of the animation. 561 // The duration of the set is 500ms, duration scale = 3. 562 verify(setListener, within(500)).onAnimationEnd(set, false); 563 verify(listener1, times(1)).onAnimationEnd(a1, false); 564 verify(listener2, times(1)).onAnimationEnd(a2, false); 565 } 566 567 /** 568 * This test sets up 10 animators playing together. We expect the start time for all animators 569 * to be the same. 570 */ 571 @Test testMultipleAnimatorsPlayTogether()572 public void testMultipleAnimatorsPlayTogether() throws Throwable { 573 Animator[] animators = new Animator[10]; 574 for (int i = 0; i < 10; i++) { 575 animators[i] = ValueAnimator.ofFloat(0f, 1f); 576 } 577 AnimatorSet set = new AnimatorSet(); 578 set.playTogether(animators); 579 set.setStartDelay(80); 580 581 Animator.AnimatorListener setListener = mock(AnimatorListenerAdapter.class); 582 set.addListener(setListener); 583 mActivityRule.runOnUiThread(() -> { 584 set.start(); 585 }); 586 SystemClock.sleep(150); 587 for (int i = 0; i < 10; i++) { 588 assertTrue(animators[i].isRunning()); 589 } 590 591 verify(setListener, within(400)).onAnimationEnd(set, false); 592 } 593 594 @Test testGetChildAnimations()595 public void testGetChildAnimations() throws Throwable { 596 Animator[] animatorArray = { xAnimator, yAnimator }; 597 598 mAnimatorSet = new AnimatorSet(); 599 mAnimatorSet.getChildAnimations(); 600 assertEquals(0, mAnimatorSet.getChildAnimations().size()); 601 mAnimatorSet.playSequentially(animatorArray); 602 assertEquals(2, mAnimatorSet.getChildAnimations().size()); 603 } 604 605 @Test testSetInterpolator()606 public void testSetInterpolator() throws Throwable { 607 xAnimator.setRepeatCount(ValueAnimator.INFINITE); 608 Animator[] animatorArray = {xAnimator, yAnimator}; 609 TimeInterpolator interpolator = new AccelerateDecelerateInterpolator(); 610 mAnimatorSet = new AnimatorSet(); 611 mAnimatorSet.playTogether(animatorArray); 612 mAnimatorSet.setInterpolator(interpolator); 613 614 assertFalse(mAnimatorSet.isRunning()); 615 startAnimation(mAnimatorSet); 616 SystemClock.sleep(100); 617 618 ArrayList<Animator> animatorList = mAnimatorSet.getChildAnimations(); 619 assertEquals(interpolator, animatorList.get(0).getInterpolator()); 620 assertEquals(interpolator, animatorList.get(1).getInterpolator()); 621 } 622 getXAnimator(Object object)623 private ObjectAnimator getXAnimator(Object object) { 624 String propertyX = "x"; 625 float startX = mActivity.mStartX; 626 float endX = mActivity.mStartX + mActivity.mDeltaX; 627 ObjectAnimator xAnimator = ObjectAnimator.ofFloat(object, propertyX, startX, endX); 628 xAnimator.setDuration(mDuration); 629 xAnimator.setRepeatCount(ValueAnimator.INFINITE); 630 xAnimator.setInterpolator(new AccelerateInterpolator()); 631 xAnimator.setRepeatMode(ValueAnimator.REVERSE); 632 return xAnimator; 633 } 634 getYAnimator(Object object)635 private ObjectAnimator getYAnimator(Object object) { 636 String property = "y"; 637 float startY = mActivity.mStartY; 638 float endY = mActivity.mStartY + mActivity.mDeltaY; 639 ObjectAnimator yAnimator = ObjectAnimator.ofFloat(object, property, startY, endY); 640 yAnimator.setDuration(mDuration); 641 yAnimator.setRepeatCount(2); 642 yAnimator.setInterpolator(new AccelerateInterpolator()); 643 yAnimator.setRepeatMode(ValueAnimator.REVERSE); 644 return yAnimator; 645 } 646 startAnimation(final AnimatorSet animatorSet)647 private void startAnimation(final AnimatorSet animatorSet) throws Throwable { 648 mActivityRule.runOnUiThread(() -> mActivity.startAnimatorSet(animatorSet)); 649 } 650 assertUnique(Object object)651 private void assertUnique(Object object) { 652 assertUnique(object, ""); 653 } 654 assertUnique(Object object, String msg)655 private void assertUnique(Object object, String msg) { 656 final int code = System.identityHashCode(object); 657 assertTrue("object should be unique " + msg + ", obj:" + object, identityHashes.add(code)); 658 659 } 660 661 @Test testClone()662 public void testClone() throws Throwable { 663 final AnimatorSet set1 = new AnimatorSet(); 664 final AnimatorListenerAdapter setListener = new AnimatorListenerAdapter() {}; 665 set1.addListener(setListener); 666 ObjectAnimator animator1 = new ObjectAnimator(); 667 animator1.setDuration(100); 668 animator1.setPropertyName("x"); 669 animator1.setIntValues(5); 670 animator1.setInterpolator(new LinearInterpolator()); 671 AnimatorListenerAdapter listener1 = new AnimatorListenerAdapter(){}; 672 AnimatorListenerAdapter listener2 = new AnimatorListenerAdapter(){}; 673 animator1.addListener(listener1); 674 675 ObjectAnimator animator2 = new ObjectAnimator(); 676 animator2.setDuration(100); 677 animator2.setInterpolator(new LinearInterpolator()); 678 animator2.addListener(listener2); 679 animator2.setPropertyName("y"); 680 animator2.setIntValues(10); 681 682 set1.playTogether(animator1, animator2); 683 684 AnimateObject target = new AnimateObject(); 685 set1.setTarget(target); 686 mActivityRule.runOnUiThread(set1::start); 687 assertTrue(set1.isStarted()); 688 689 animator1.getListeners(); 690 AnimatorSet set2 = set1.clone(); 691 assertFalse(set2.isStarted()); 692 693 assertUnique(set1); 694 assertUnique(animator1); 695 assertUnique(animator2); 696 697 assertUnique(set2); 698 assertEquals(2, set2.getChildAnimations().size()); 699 700 Animator clone1 = set2.getChildAnimations().get(0); 701 Animator clone2 = set2.getChildAnimations().get(1); 702 703 for (Animator animator : set2.getChildAnimations()) { 704 assertUnique(animator); 705 } 706 707 assertTrue(clone1.getListeners().contains(listener1)); 708 assertTrue(clone2.getListeners().contains(listener2)); 709 710 assertTrue(set2.getListeners().contains(setListener)); 711 712 for (Animator.AnimatorListener listener : set1.getListeners()) { 713 assertTrue(set2.getListeners().contains(listener)); 714 } 715 716 assertEquals(animator1.getDuration(), clone1.getDuration()); 717 assertEquals(animator2.getDuration(), clone2.getDuration()); 718 assertSame(animator1.getInterpolator(), clone1.getInterpolator()); 719 assertSame(animator2.getInterpolator(), clone2.getInterpolator()); 720 } 721 722 /** 723 * Testing seeking in an AnimatorSet containing sequential animators. 724 */ 725 @Test testSeeking()726 public void testSeeking() throws Throwable { 727 final AnimatorSet set = new AnimatorSet(); 728 final ValueAnimator a1 = ValueAnimator.ofFloat(0f, 150f); 729 a1.setDuration(150); 730 final ValueAnimator a2 = ValueAnimator.ofFloat(150f, 250f); 731 a2.setDuration(100); 732 final ValueAnimator a3 = ValueAnimator.ofFloat(250f, 300f); 733 a3.setDuration(50); 734 735 a1.setInterpolator(null); 736 a2.setInterpolator(null); 737 a3.setInterpolator(null); 738 739 set.playSequentially(a1, a2, a3); 740 741 set.setCurrentPlayTime(100); 742 assertEquals(100f, (Float) a1.getAnimatedValue(), EPSILON); 743 assertEquals(150f, (Float) a2.getAnimatedValue(), EPSILON); 744 assertEquals(250f, (Float) a3.getAnimatedValue(), EPSILON); 745 746 set.setCurrentPlayTime(280); 747 assertEquals(150f, (Float) a1.getAnimatedValue(), EPSILON); 748 assertEquals(250f, (Float) a2.getAnimatedValue(), EPSILON); 749 assertEquals(280f, (Float) a3.getAnimatedValue(), EPSILON); 750 751 AnimatorListenerAdapter setListener = new AnimatorListenerAdapter() { 752 @Override 753 public void onAnimationEnd(Animator animation) { 754 super.onAnimationEnd(animation); 755 assertEquals(150f, (Float) a1.getAnimatedValue(), EPSILON); 756 assertEquals(250f, (Float) a2.getAnimatedValue(), EPSILON); 757 assertEquals(300f, (Float) a3.getAnimatedValue(), EPSILON); 758 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 assertTrue(set.getCurrentPlayTime() >= 200); 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 951 /** 952 * This test sets up an AnimatorSet that contains two sequential animations. The first animation 953 * is infinite, the second animation therefore has an infinite start time. This test verifies 954 * that the infinite start time is handled correctly. 955 */ 956 @Test testInfiniteStartTime()957 public void testInfiniteStartTime() throws Throwable { 958 ValueAnimator a1 = ValueAnimator.ofFloat(0f, 1f); 959 a1.setRepeatCount(ValueAnimator.INFINITE); 960 ValueAnimator a2 = ValueAnimator.ofFloat(0f, 1f); 961 962 AnimatorSet set = new AnimatorSet(); 963 set.playSequentially(a1, a2); 964 965 mActivityRule.runOnUiThread(() -> { 966 set.start(); 967 }); 968 969 assertEquals(Animator.DURATION_INFINITE, set.getTotalDuration()); 970 971 mActivityRule.runOnUiThread(() -> { 972 set.end(); 973 }); 974 } 975 976 static class TargetObj { 977 public float value = 0; 978 setVal(float value)979 public void setVal(float value) { 980 this.value = value; 981 } 982 } 983 984 class AnimateObject { 985 int x = 1; 986 int y = 2; 987 } 988 989 static class MyListener extends AnimatorListenerAdapter { 990 boolean mStartIsCalled = false; 991 boolean mEndIsCalled = false; 992 onAnimationStart(Animator animation)993 public void onAnimationStart(Animator animation) { 994 mStartIsCalled = true; 995 } 996 onAnimationEnd(Animator animation)997 public void onAnimationEnd(Animator animation) { 998 mEndIsCalled = true; 999 } 1000 } 1001 1002 static class MyValueAnimator extends ValueAnimator { 1003 boolean mStartCalled = false; 1004 @Override start()1005 public void start() { 1006 // Do not call super intentionally. 1007 mStartCalled = true; 1008 } 1009 } 1010 } 1011