1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.view.animation.cts; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertNotNull; 22 import static org.junit.Assert.assertNotSame; 23 import static org.junit.Assert.assertNull; 24 import static org.junit.Assert.assertSame; 25 import static org.junit.Assert.assertTrue; 26 import static org.mockito.Mockito.atLeastOnce; 27 import static org.mockito.Mockito.mock; 28 import static org.mockito.Mockito.never; 29 import static org.mockito.Mockito.reset; 30 import static org.mockito.Mockito.times; 31 import static org.mockito.Mockito.verify; 32 import static org.mockito.Mockito.verifyZeroInteractions; 33 34 import android.app.Activity; 35 import android.app.Instrumentation; 36 import android.content.res.XmlResourceParser; 37 import android.os.SystemClock; 38 import android.support.test.InstrumentationRegistry; 39 import android.support.test.filters.LargeTest; 40 import android.support.test.filters.MediumTest; 41 import android.support.test.rule.ActivityTestRule; 42 import android.support.test.runner.AndroidJUnit4; 43 import android.util.AttributeSet; 44 import android.util.Xml; 45 import android.view.View; 46 import android.view.animation.AccelerateDecelerateInterpolator; 47 import android.view.animation.AccelerateInterpolator; 48 import android.view.animation.Animation; 49 import android.view.animation.Animation.AnimationListener; 50 import android.view.animation.AnimationUtils; 51 import android.view.animation.DecelerateInterpolator; 52 import android.view.animation.Interpolator; 53 import android.view.animation.Transformation; 54 import android.view.cts.R; 55 56 import com.android.compatibility.common.util.PollingCheck; 57 58 import org.junit.Before; 59 import org.junit.Rule; 60 import org.junit.Test; 61 import org.junit.runner.RunWith; 62 63 import java.util.concurrent.CountDownLatch; 64 import java.util.concurrent.TimeUnit; 65 66 /** 67 * Test {@link Animation}. 68 */ 69 @MediumTest 70 @RunWith(AndroidJUnit4.class) 71 public class AnimationTest { 72 private static final float COMPARISON_DELTA = 0.001f; 73 74 /** It is defined in R.anim.accelerate_alpha */ 75 private static final int ACCELERATE_ALPHA_DURATION = 1000; 76 77 /** It is defined in R.anim.decelerate_alpha */ 78 private static final int DECELERATE_ALPHA_DURATION = 2000; 79 80 private static final int CANCELATION_TIMEOUT = 1000; 81 82 private Instrumentation mInstrumentation; 83 private Activity mActivity; 84 85 @Rule 86 public ActivityTestRule<AnimationTestCtsActivity> mActivityRule = 87 new ActivityTestRule<>(AnimationTestCtsActivity.class); 88 89 @Before setup()90 public void setup() { 91 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 92 mActivity = mActivityRule.getActivity(); 93 } 94 95 @Test testConstructor()96 public void testConstructor() { 97 XmlResourceParser parser = mActivity.getResources().getAnimation(R.anim.alpha); 98 AttributeSet attrs = Xml.asAttributeSet(parser); 99 new Animation(mActivity, attrs) { 100 }; 101 102 new Animation() { 103 }; 104 } 105 106 @Test testAccessInterpolator()107 public void testAccessInterpolator() { 108 // check default interpolator 109 MyAnimation myAnimation = new MyAnimation(); 110 Interpolator interpolator = myAnimation.getInterpolator(); 111 assertTrue(interpolator instanceof AccelerateDecelerateInterpolator); // issue 1561186. 112 113 myAnimation.ensureInterpolator(); 114 assertSame(interpolator, myAnimation.getInterpolator()); 115 116 myAnimation.setInterpolator(null); 117 assertNull(myAnimation.getInterpolator()); 118 myAnimation.ensureInterpolator(); 119 interpolator = myAnimation.getInterpolator(); 120 assertTrue(interpolator instanceof AccelerateDecelerateInterpolator); 121 122 Animation animation = AnimationUtils.loadAnimation(mActivity, R.anim.decelerate_alpha); 123 interpolator = animation.getInterpolator(); 124 assertNotNull(interpolator); 125 assertTrue(interpolator instanceof DecelerateInterpolator); 126 127 animation = AnimationUtils.loadAnimation(mActivity, R.anim.accelerate_alpha); 128 interpolator = animation.getInterpolator(); 129 assertNotNull(interpolator); 130 assertTrue(interpolator instanceof AccelerateInterpolator); 131 } 132 133 @Test testDefaultFill()134 public void testDefaultFill() { 135 Animation animation = new Animation() { 136 }; 137 assertTrue(animation.getFillBefore()); 138 assertFalse(animation.getFillAfter()); 139 } 140 141 @Test testAccessFill()142 public void testAccessFill() throws Throwable { 143 View animWindow = mActivity.findViewById(R.id.anim_window); 144 // XML file of R.anim.accelerate_alpha 145 // <alpha xmlns:android="http://schemas.android.com/apk/res/android" 146 // android:interpolator="@android:anim/accelerate_interpolator" 147 // android:fromAlpha="0.1" 148 // android:toAlpha="0.9" 149 // android:duration="1000" /> 150 Animation animation = AnimationUtils.loadAnimation(mActivity, R.anim.accelerate_alpha); 151 assertFalse(animation.isFillEnabled()); 152 assertTrue(animation.getFillBefore()); 153 assertFalse(animation.getFillAfter()); 154 155 AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow, 156 animation); 157 158 // fillBefore and fillAfter are ignored when fillEnabled is false 159 Transformation transformation = new Transformation(); 160 // check alpha before start 161 animation.getTransformation(animation.getStartTime() - 1, transformation); 162 float alpha = transformation.getAlpha(); 163 assertEquals(0.1f, alpha, COMPARISON_DELTA); // issue 1698355 164 165 transformation = new Transformation(); 166 // check alpha after the end 167 animation.getTransformation(animation.getStartTime() + animation.getDuration() + 1, 168 transformation); 169 alpha = transformation.getAlpha(); 170 assertEquals(0.9f, alpha, COMPARISON_DELTA); // issue 1698355 171 172 animation.setFillEnabled(true); 173 animation.setFillBefore(false); 174 assertTrue(animation.isFillEnabled()); 175 assertFalse(animation.getFillBefore()); 176 assertFalse(animation.getFillAfter()); 177 AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow, 178 animation); 179 180 transformation = new Transformation(); 181 animation.getTransformation(animation.getStartTime() - 1, transformation); 182 alpha = transformation.getAlpha(); 183 assertEquals(1.0f, alpha, COMPARISON_DELTA); 184 185 transformation = new Transformation(); 186 animation.getTransformation(animation.getStartTime() + animation.getDuration() + 1, 187 transformation); 188 alpha = transformation.getAlpha(); 189 assertEquals(1.0f, alpha, COMPARISON_DELTA); 190 191 animation.setFillBefore(true); 192 animation.setFillAfter(true); 193 assertTrue(animation.isFillEnabled()); 194 assertTrue(animation.getFillBefore()); 195 assertTrue(animation.getFillAfter()); 196 AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow, 197 animation); 198 199 transformation = new Transformation(); 200 animation.getTransformation(animation.getStartTime() - 1, transformation); 201 alpha = transformation.getAlpha(); 202 assertEquals(0.1f, alpha, COMPARISON_DELTA); 203 204 transformation = new Transformation(); 205 animation.getTransformation(animation.getStartTime() + animation.getDuration() + 1, 206 transformation); 207 alpha = transformation.getAlpha(); 208 assertEquals(0.9f, alpha, COMPARISON_DELTA); 209 } 210 211 @Test testComputeDurationHint()212 public void testComputeDurationHint() { 213 // start offset is 0, duration is 2000, repeat count is 0. 214 Animation animation = AnimationUtils.loadAnimation(mActivity, R.anim.decelerate_alpha); 215 assertEquals(2000, animation.computeDurationHint()); 216 217 // start offset is 0, duration is 2000, repeat count is 2. 218 animation.setRepeatCount(2); 219 assertEquals(6000, animation.computeDurationHint()); 220 221 // start offset is 800, duration is 2000, repeat count is 2. 222 animation.setStartOffset(800); 223 assertEquals(8400, animation.computeDurationHint()); 224 } 225 226 @Test testRepeatAnimation()227 public void testRepeatAnimation() throws Throwable { 228 // check default repeatMode 229 Animation animation = new Animation() { 230 }; 231 assertEquals(Animation.RESTART, animation.getRepeatMode()); 232 233 final View animWindow = mActivity.findViewById(R.id.anim_window); 234 235 // XML file of R.anim.decelerate_alpha 236 // <alpha xmlns:android="http://schemas.android.com/apk/res/android" 237 // android:interpolator="@android:anim/decelerate_interpolator" 238 // android:fromAlpha="0.0" 239 // android:toAlpha="1.0" 240 // android:duration="2000" /> 241 final Animation anim = AnimationUtils.loadAnimation(mActivity, R.anim.decelerate_alpha); 242 assertEquals(Animation.RESTART, animation.getRepeatMode()); 243 long duration = anim.getDuration(); 244 assertEquals(DECELERATE_ALPHA_DURATION, duration); 245 // repeat count is 0, repeat mode does not make sense. 246 AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow, anim); 247 248 // test repeat mode REVERSE 249 anim.setRepeatCount(1); 250 anim.setRepeatMode(Animation.REVERSE); 251 // we have to PollingCheck the animation status on test thread, 252 // it cannot be done on UI thread, so we invoke runOnUiThread method here. 253 mActivityRule.runOnUiThread(() -> animWindow.startAnimation(anim)); 254 255 // check whether animation has started 256 PollingCheck.waitFor(anim::hasStarted); 257 258 Transformation transformation = new Transformation(); 259 long startTime = anim.getStartTime(); 260 anim.getTransformation(startTime, transformation); 261 float alpha1 = transformation.getAlpha(); 262 assertEquals(0.0f, alpha1, COMPARISON_DELTA); 263 264 anim.getTransformation(startTime + 1000, transformation); 265 float alpha2 = transformation.getAlpha(); 266 267 anim.getTransformation(startTime + 2000, transformation); 268 float alpha3 = transformation.getAlpha(); 269 assertEquals(1.0f, alpha3, COMPARISON_DELTA); 270 271 // wait for animation has ended. 272 // timeout is larger than duration, in case the system is sluggish 273 PollingCheck.waitFor(duration * 2 + 1000, anim::hasEnded); 274 275 // get start time of reversing. 276 startTime = anim.getStartTime(); 277 anim.getTransformation(startTime + 3000, transformation); 278 float alpha4 = transformation.getAlpha(); 279 280 anim.getTransformation(startTime + 4000, transformation); 281 float alpha5 = transformation.getAlpha(); 282 assertEquals(0.0f, alpha5, COMPARISON_DELTA); 283 284 // check decelerating delta alpha when reverse. alpha should change form 0.0f to 1.0f 285 // and then from 1.0f to 0.0f 286 float delta1 = alpha2 - alpha1; 287 float delta2 = alpha3 - alpha2; 288 // the animation plays backward 289 float delta3 = alpha3 - alpha4; 290 float delta4 = alpha4 - alpha5; 291 assertTrue(delta1 > delta2); 292 assertTrue(delta3 > delta4); 293 294 // test repeat mode RESTART 295 anim.setRepeatMode(Animation.RESTART); 296 // we have to PollingCheck the animation status on test thread, 297 // it cannot be done on UI thread, so we invoke runOnUiThread method here. 298 mActivityRule.runOnUiThread(() -> animWindow.startAnimation(anim)); 299 300 // check whether animation has started 301 PollingCheck.waitFor(anim::hasStarted); 302 303 transformation = new Transformation(); 304 startTime = anim.getStartTime(); 305 anim.getTransformation(startTime, transformation); 306 alpha1 = transformation.getAlpha(); 307 assertEquals(0.0f, alpha1, COMPARISON_DELTA); 308 309 anim.getTransformation(startTime + 1000, transformation); 310 alpha2 = transformation.getAlpha(); 311 312 anim.getTransformation(startTime + 2000, transformation); 313 alpha3 = transformation.getAlpha(); 314 assertEquals(1.0f, alpha3, COMPARISON_DELTA); 315 316 // wait for animation has ended. 317 // timeout is larger than duration, in case the system is sluggish 318 PollingCheck.waitFor(duration * 2 + 1000, anim::hasEnded); 319 320 // get start time of restarting. 321 startTime = anim.getStartTime(); 322 anim.getTransformation(startTime + 3000, transformation); 323 alpha4 = transformation.getAlpha(); 324 325 anim.getTransformation(startTime + 4000, transformation); 326 alpha5 = transformation.getAlpha(); 327 assertEquals(1.0f, alpha5, COMPARISON_DELTA); 328 329 // check decelerating delta alpha when restart. alpha should change form 0.0f to 1.0f 330 // and then from 0.0f to 1.0f again 331 delta1 = alpha2 - 0.0f; 332 delta2 = alpha3 - alpha2; 333 // the animation restarts from the beginning 334 delta3 = alpha4 - 0.0f; 335 delta4 = alpha5 - alpha4; 336 assertTrue(delta1 > delta2); 337 assertTrue(delta3 > delta4); 338 } 339 340 @Test testAccessStartOffset()341 public void testAccessStartOffset() throws Throwable { 342 final long startOffset = 800; 343 // check default startOffset 344 Animation animation = new Animation() { 345 }; 346 assertEquals(0, animation.getStartOffset()); 347 348 View animWindow = mActivity.findViewById(R.id.anim_window); 349 // XML file of R.anim.accelerate_alpha 350 // <alpha xmlns:android="http://schemas.android.com/apk/res/android" 351 // android:interpolator="@android:anim/accelerate_interpolator" 352 // android:fromAlpha="0.1" 353 // android:toAlpha="0.9" 354 // android:duration="1000" /> 355 animation = AnimationUtils.loadAnimation(mActivity, R.anim.accelerate_alpha); 356 animation.setStartOffset(startOffset); 357 assertEquals(startOffset, animation.getStartOffset()); 358 359 AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow, 360 animation, ACCELERATE_ALPHA_DURATION + startOffset); 361 362 Transformation transformation = new Transformation(); 363 long startTime = animation.getStartTime(); 364 animation.getTransformation(startTime, transformation); 365 float alpha1 = transformation.getAlpha(); 366 assertEquals(0.1f, alpha1, COMPARISON_DELTA); 367 368 animation.getTransformation(startTime + 400, transformation); 369 float alpha2 = transformation.getAlpha(); 370 // alpha is 0.1f during start offset 371 assertEquals(0.1f, alpha2, COMPARISON_DELTA); 372 373 animation.getTransformation(startTime + startOffset, transformation); 374 float alpha3 = transformation.getAlpha(); 375 // alpha is 0.1f during start offset 376 assertEquals(0.1f, alpha3, COMPARISON_DELTA); 377 378 animation.getTransformation(startTime + startOffset + 1, transformation); 379 float alpha4 = transformation.getAlpha(); 380 // alpha is lager than 0.1f after start offset 381 assertTrue(alpha4 > 0.1f); 382 } 383 384 @Test testRunAccelerateAlpha()385 public void testRunAccelerateAlpha() throws Throwable { 386 // check default startTime 387 Animation animation = new Animation() { 388 }; 389 assertEquals(Animation.START_ON_FIRST_FRAME, animation.getStartTime()); 390 391 long currentTime = AnimationUtils.currentAnimationTimeMillis(); 392 animation.setStartTime(currentTime); 393 assertEquals(currentTime, animation.getStartTime()); 394 395 View animWindow = mActivity.findViewById(R.id.anim_window); 396 397 // XML file of R.anim.accelerate_alpha 398 // <alpha xmlns:android="http://schemas.android.com/apk/res/android" 399 // android:interpolator="@android:anim/accelerate_interpolator" 400 // android:fromAlpha="0.1" 401 // android:toAlpha="0.9" 402 // android:duration="1000" /> 403 Animation anim = AnimationUtils.loadAnimation(mActivity, R.anim.accelerate_alpha); 404 assertEquals(Animation.START_ON_FIRST_FRAME, anim.getStartTime()); 405 assertFalse(anim.hasStarted()); 406 AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow, anim); 407 } 408 409 @Test testGetTransformation()410 public void testGetTransformation() throws Throwable { 411 final View animWindow = mActivity.findViewById(R.id.anim_window); 412 413 // XML file of R.anim.accelerate_alpha 414 // <alpha xmlns:android="http://schemas.android.com/apk/res/android" 415 // android:interpolator="@android:anim/accelerate_interpolator" 416 // android:fromAlpha="0.1" 417 // android:toAlpha="0.9" 418 // android:duration="1000" /> 419 final Animation anim = AnimationUtils.loadAnimation(mActivity, R.anim.accelerate_alpha); 420 assertFalse(anim.hasStarted()); 421 422 // we have to PollingCheck the animation status on test thread, 423 // it cannot be done on UI thread, so we invoke runOnUiThread method here. 424 mActivityRule.runOnUiThread(() -> animWindow.startAnimation(anim)); 425 426 // check whether animation has started 427 PollingCheck.waitFor(anim::hasStarted); 428 429 // check transformation objects that is provided by the 430 // caller and will be filled in by the animation. 431 Transformation transformation = new Transformation(); 432 long startTime = anim.getStartTime(); 433 assertTrue(anim.getTransformation(startTime, transformation)); 434 float alpha1 = transformation.getAlpha(); 435 assertEquals(0.1f, alpha1, COMPARISON_DELTA); 436 437 assertTrue(anim.getTransformation(startTime + 250, transformation)); 438 float alpha2 = transformation.getAlpha(); 439 440 assertTrue(anim.getTransformation(startTime + 500, transformation)); 441 float alpha3 = transformation.getAlpha(); 442 443 assertTrue(anim.getTransformation(startTime + 750, transformation)); 444 float alpha4 = transformation.getAlpha(); 445 446 // wait for animation has ended. 447 // timeout is larger than duration, in case the system is sluggish 448 PollingCheck.waitFor(2000, anim::hasEnded); 449 450 assertFalse(anim.getTransformation(startTime + 1000, transformation)); 451 float alpha5 = transformation.getAlpha(); 452 assertEquals(0.9f, alpha5, COMPARISON_DELTA); 453 454 // check decelerating delta alpha 455 float delta1 = alpha2 - alpha1; 456 float delta2 = alpha3 - alpha2; 457 float delta3 = alpha4 - alpha3; 458 float delta4 = alpha5 - alpha4; 459 assertTrue(delta1 < delta2); 460 assertTrue(delta2 < delta3); 461 assertTrue(delta3 < delta4); 462 } 463 464 @Test 465 public void testAccessZAdjustment() { 466 // check default zAdjustment 467 Animation animation = new Animation() { 468 }; 469 assertEquals(Animation.ZORDER_NORMAL, animation.getZAdjustment()); 470 471 animation = AnimationUtils.loadAnimation(mActivity, R.anim.accelerate_alpha); 472 assertEquals(Animation.ZORDER_NORMAL, animation.getZAdjustment()); 473 474 animation.setZAdjustment(Animation.ZORDER_TOP); 475 assertEquals(Animation.ZORDER_TOP, animation.getZAdjustment()); 476 477 animation.setZAdjustment(Animation.ZORDER_BOTTOM); 478 assertEquals(Animation.ZORDER_BOTTOM, animation.getZAdjustment()); 479 } 480 481 @Test 482 public void testInitialize() { 483 Animation animation = new Animation() { 484 }; 485 486 assertFalse(animation.isInitialized()); 487 animation.initialize(320, 480, 320, 480); 488 assertTrue(animation.isInitialized()); 489 } 490 491 @Test 492 public void testResolveSize() { 493 MyAnimation myAnimation = new MyAnimation(); 494 495 assertEquals(1.0f, myAnimation.resolveSize(Animation.ABSOLUTE, 1.0f, 0, 0), 496 COMPARISON_DELTA); 497 assertEquals(2.0f, myAnimation.resolveSize(Animation.ABSOLUTE, 2.0f, 0, 0), 498 COMPARISON_DELTA); 499 500 assertEquals(6.0f, myAnimation.resolveSize(Animation.RELATIVE_TO_SELF, 3.0f, 2, 0), 501 COMPARISON_DELTA); 502 assertEquals(9.0f, myAnimation.resolveSize(Animation.RELATIVE_TO_SELF, 3.0f, 3, 0), 503 COMPARISON_DELTA); 504 505 assertEquals(18.0f, myAnimation.resolveSize(Animation.RELATIVE_TO_PARENT, 3.0f, 0, 6), 506 COMPARISON_DELTA); 507 assertEquals(12.0f, myAnimation.resolveSize(Animation.RELATIVE_TO_PARENT, 3.0f, 0, 4), 508 COMPARISON_DELTA); 509 510 int unknownType = 7; 511 assertEquals(8.0f, myAnimation.resolveSize(unknownType, 8.0f, 3, 4), COMPARISON_DELTA); 512 assertEquals(10.0f, myAnimation.resolveSize(unknownType, 10.0f, 3, 4), COMPARISON_DELTA); 513 } 514 515 @Test 516 public void testRestrictDuration() { 517 Animation animation = new Animation() { 518 }; 519 520 animation.setStartOffset(1000); 521 animation.restrictDuration(500); 522 assertEquals(500, animation.getStartOffset()); 523 assertEquals(0, animation.getDuration()); 524 assertEquals(0, animation.getRepeatCount()); 525 526 animation.setStartOffset(1000); 527 animation.setDuration(1000); 528 animation.restrictDuration(1500); 529 assertEquals(500, animation.getDuration()); 530 531 animation.setStartOffset(1000); 532 animation.setDuration(1000); 533 animation.setRepeatCount(3); 534 animation.restrictDuration(4500); 535 assertEquals(1, animation.getRepeatCount()); 536 } 537 538 @Test 539 public void testScaleCurrentDuration() { 540 Animation animation = new Animation() { 541 }; 542 543 animation.setDuration(10); 544 animation.scaleCurrentDuration(0); 545 assertEquals(0, animation.getDuration()); 546 547 animation.setDuration(10); 548 animation.scaleCurrentDuration(2); 549 assertEquals(20, animation.getDuration()); 550 551 animation.setDuration(10); 552 animation.scaleCurrentDuration(-1); 553 assertEquals(-10, animation.getDuration()); 554 } 555 556 @LargeTest 557 @Test 558 public void testSetAnimationListener() throws Throwable { 559 final View animWindow = mActivity.findViewById(R.id.anim_window); 560 561 // XML file of R.anim.accelerate_alpha 562 // <alpha xmlns:android="http://schemas.android.com/apk/res/android" 563 // android:interpolator="@android:anim/accelerate_interpolator" 564 // android:fromAlpha="0.1" 565 // android:toAlpha="0.9" 566 // android:duration="1000" /> 567 final Animation anim = AnimationUtils.loadAnimation(mActivity, R.anim.accelerate_alpha); 568 final AnimationListener listener = mock(AnimationListener.class); 569 anim.setAnimationListener(listener); 570 verifyZeroInteractions(listener); 571 572 AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow, anim); 573 verify(listener, times(1)).onAnimationStart(anim); 574 verify(listener, times(1)).onAnimationEnd(anim); 575 verify(listener, never()).onAnimationRepeat(anim); 576 577 reset(listener); 578 anim.setRepeatCount(2); 579 anim.setRepeatMode(Animation.REVERSE); 580 581 AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow, anim, 582 3000); 583 verify(listener, times(1)).onAnimationStart(anim); 584 verify(listener, times(2)).onAnimationRepeat(anim); 585 verify(listener, times(1)).onAnimationEnd(anim); 586 587 reset(listener); 588 // onAnimationEnd will not be invoked and animation should not end 589 anim.setRepeatCount(Animation.INFINITE); 590 591 mActivityRule.runOnUiThread(() -> animWindow.startAnimation(anim)); 592 // Verify that our animation doesn't call listener's onAnimationEnd even after a long 593 // period of time. We just sleep and then verify what's happened with the listener. 594 SystemClock.sleep(4 * ACCELERATE_ALPHA_DURATION); 595 596 verify(listener, times(1)).onAnimationStart(anim); 597 verify(listener, atLeastOnce()).onAnimationRepeat(anim); 598 verify(listener, never()).onAnimationEnd(anim); 599 } 600 601 @Test 602 public void testStart() { 603 Animation animation = AnimationUtils.loadAnimation(mActivity, R.anim.accelerate_alpha); 604 animation.setStartTime(0); 605 606 animation.start(); 607 assertEquals(Animation.START_ON_FIRST_FRAME, animation.getStartTime()); 608 } 609 610 @Test 611 public void testStartNow() { 612 Animation animation = AnimationUtils.loadAnimation(mActivity, R.anim.accelerate_alpha); 613 animation.setStartTime(0); 614 615 long currentTime = AnimationUtils.currentAnimationTimeMillis(); 616 animation.startNow(); 617 assertEquals(currentTime, animation.getStartTime(), 100); 618 } 619 620 @Test 621 public void testWillChangeBounds() { 622 Animation animation = new Animation() { 623 }; 624 625 assertTrue(animation.willChangeBounds()); 626 } 627 628 @Test 629 public void testWillChangeTransformationMatrix() { 630 Animation animation = new Animation() { 631 }; 632 633 assertTrue(animation.willChangeTransformationMatrix()); 634 } 635 636 @Test 637 public void testClone() throws CloneNotSupportedException { 638 MyAnimation myAnimation = new MyAnimation(); 639 myAnimation.setDuration(3000); 640 myAnimation.setFillAfter(true); 641 myAnimation.setFillBefore(false); 642 myAnimation.setFillEnabled(true); 643 myAnimation.setStartTime(1000); 644 myAnimation.setRepeatCount(10); 645 myAnimation.setRepeatMode(Animation.REVERSE); 646 647 Animation cloneAnimation = myAnimation.clone(); 648 assertNotSame(myAnimation, cloneAnimation); 649 assertEquals(myAnimation.getDuration(), cloneAnimation.getDuration()); 650 assertEquals(myAnimation.getFillAfter(), cloneAnimation.getFillAfter()); 651 assertEquals(myAnimation.getFillBefore(), cloneAnimation.getFillBefore()); 652 assertEquals(myAnimation.isFillEnabled(), cloneAnimation.isFillEnabled()); 653 assertEquals(myAnimation.getStartOffset(), cloneAnimation.getStartOffset()); 654 assertEquals(myAnimation.getRepeatCount(), cloneAnimation.getRepeatCount()); 655 assertEquals(myAnimation.getRepeatMode(), cloneAnimation.getRepeatMode()); 656 } 657 658 @Test 659 public void testCancelImmediately() throws Throwable { 660 MyAnimation anim = new MyAnimation(); 661 final CountDownLatch latch1 = new CountDownLatch(1); 662 runCanceledAnimation(anim, latch1, false, false); 663 assertTrue(latch1.await(CANCELATION_TIMEOUT, TimeUnit.MILLISECONDS)); 664 assertFalse(anim.isStillAnimating()); 665 } 666 667 @Test 668 public void testRepeatingCancelImmediately() throws Throwable { 669 MyAnimation anim = new MyAnimation(); 670 final CountDownLatch latch2 = new CountDownLatch(1); 671 runCanceledAnimation(anim, latch2, true, false); 672 assertTrue(latch2.await(CANCELATION_TIMEOUT, TimeUnit.MILLISECONDS)); 673 assertFalse(anim.isStillAnimating()); 674 } 675 676 @Test 677 public void testCancelDelayed() throws Throwable { 678 MyAnimation anim = new MyAnimation(); 679 final CountDownLatch latch3 = new CountDownLatch(1); 680 runCanceledAnimation(anim, latch3, false, true); 681 assertTrue(latch3.await(CANCELATION_TIMEOUT, TimeUnit.MILLISECONDS)); 682 assertFalse(anim.isStillAnimating()); 683 } 684 685 @Test 686 public void testRepeatingCancelDelayed() throws Throwable { 687 MyAnimation anim = new MyAnimation(); 688 final CountDownLatch latch4 = new CountDownLatch(1); 689 runCanceledAnimation(anim, latch4, true, true); 690 assertTrue(latch4.await(CANCELATION_TIMEOUT, TimeUnit.MILLISECONDS)); 691 assertFalse(anim.isStillAnimating()); 692 } 693 694 private void runCanceledAnimation(final MyAnimation anim, final CountDownLatch latch, 695 final boolean repeating, final boolean delayed) throws Throwable { 696 // The idea behind this test is that canceling an Animation should result in 697 // it ending, which means not having its getTransformation() method called 698 // anymore. The trick is that cancel() will still allow one more frame to run, 699 // so we have to insert some delay between when we cancel and when we can check 700 // whether it is still animating. 701 final View view = mActivity.findViewById(R.id.anim_window); 702 mActivityRule.runOnUiThread(() -> { 703 anim.setDuration(delayed ? 150 : 100); 704 if (repeating) { 705 anim.setRepeatCount(Animation.INFINITE); 706 } 707 view.startAnimation(anim); 708 if (!delayed) { 709 anim.cancel(); 710 } else { 711 view.postDelayed(anim::cancel, 50); 712 } 713 view.postDelayed(() -> { 714 anim.setStillAnimating(false); 715 view.postDelayed(latch::countDown, 50); 716 }, delayed ? 100 : 50); 717 }); 718 } 719 720 private class MyAnimation extends Animation { 721 boolean mStillAnimating = false; 722 723 @Override ensureInterpolator()724 protected void ensureInterpolator() { 725 super.ensureInterpolator(); 726 } 727 728 @Override resolveSize(int type, float value, int size, int parentSize)729 protected float resolveSize(int type, float value, int size, int parentSize) { 730 return super.resolveSize(type, value, size, parentSize); 731 } 732 733 @Override clone()734 protected Animation clone() throws CloneNotSupportedException { 735 return super.clone(); 736 } 737 setStillAnimating(boolean value)738 public void setStillAnimating(boolean value) { 739 mStillAnimating = value; 740 } 741 isStillAnimating()742 public boolean isStillAnimating() { 743 return mStillAnimating; 744 } 745 746 @Override getTransformation(long currentTime, Transformation outTransformation)747 public boolean getTransformation(long currentTime, Transformation outTransformation) { 748 mStillAnimating = true; 749 return super.getTransformation(currentTime, outTransformation); 750 } 751 } 752 } 753