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.assertNotNull; 23 import static org.junit.Assert.assertTrue; 24 import static org.mockito.Mockito.atLeast; 25 import static org.mockito.Mockito.mock; 26 import static org.mockito.Mockito.timeout; 27 import static org.mockito.Mockito.times; 28 import static org.mockito.Mockito.verify; 29 30 import android.animation.Animator; 31 import android.animation.Animator.AnimatorListener; 32 import android.animation.AnimatorListenerAdapter; 33 import android.animation.ObjectAnimator; 34 import android.animation.PropertyValuesHolder; 35 import android.animation.TimeInterpolator; 36 import android.animation.TypeEvaluator; 37 import android.animation.ValueAnimator; 38 import android.animation.ValueAnimator.AnimatorUpdateListener; 39 import android.graphics.Color; 40 import android.graphics.PointF; 41 import android.os.SystemClock; 42 import android.util.Range; 43 import android.view.animation.AccelerateInterpolator; 44 import android.view.animation.LinearInterpolator; 45 46 import androidx.test.InstrumentationRegistry; 47 import androidx.test.annotation.UiThreadTest; 48 import androidx.test.filters.LargeTest; 49 import androidx.test.rule.ActivityTestRule; 50 import androidx.test.runner.AndroidJUnit4; 51 52 import org.junit.AfterClass; 53 import org.junit.Before; 54 import org.junit.BeforeClass; 55 import org.junit.Rule; 56 import org.junit.Test; 57 import org.junit.runner.RunWith; 58 59 import java.util.concurrent.CountDownLatch; 60 import java.util.concurrent.TimeUnit; 61 62 @LargeTest 63 @RunWith(AndroidJUnit4.class) 64 public class ValueAnimatorTest { 65 private static final float EPSILON = 0.0001f; 66 private static float sPreviousAnimatorScale = 1.0f; 67 68 private AnimationActivity mActivity; 69 private ValueAnimator mValueAnimator; 70 private final long mDuration = 2000; 71 72 @Rule 73 public ActivityTestRule<AnimationActivity> mActivityRule = 74 new ActivityTestRule<>(AnimationActivity.class); 75 76 @Before setup()77 public void setup() { 78 InstrumentationRegistry.getInstrumentation().setInTouchMode(false); 79 mActivity = mActivityRule.getActivity(); 80 mValueAnimator = mActivity.createAnimatorWithDuration(mDuration); 81 } 82 83 @BeforeClass beforeClass()84 public static void beforeClass() { 85 sPreviousAnimatorScale = ValueAnimator.getDurationScale(); 86 ValueAnimator.setDurationScale(1.0f); 87 } 88 89 @AfterClass afterClass()90 public static void afterClass() { 91 ValueAnimator.setDurationScale(sPreviousAnimatorScale); 92 } 93 94 @Test testDuration()95 public void testDuration() throws Throwable { 96 ValueAnimator valueAnimatorLocal = mActivity.createAnimatorWithDuration(mDuration); 97 startAnimation(valueAnimatorLocal); 98 assertEquals(mDuration, valueAnimatorLocal.getDuration()); 99 } 100 101 @Test testIsRunning()102 public void testIsRunning() throws Throwable { 103 assertFalse(mValueAnimator.isRunning()); 104 startAnimation(mValueAnimator); 105 ValueAnimator valueAnimatorReturned = mActivity.view.bounceYAnimator; 106 assertTrue(valueAnimatorReturned.isRunning()); 107 } 108 109 @Test testIsStarted()110 public void testIsStarted() throws Throwable { 111 assertFalse(mValueAnimator.isRunning()); 112 assertFalse(mValueAnimator.isStarted()); 113 long startDelay = 10000; 114 mValueAnimator.setStartDelay(startDelay); 115 startAnimation(mValueAnimator); 116 assertFalse(mValueAnimator.isRunning()); 117 assertTrue(mValueAnimator.isStarted()); 118 } 119 120 @Test testRepeatMode()121 public void testRepeatMode() throws Throwable { 122 ValueAnimator mValueAnimator = mActivity.createAnimatorWithRepeatMode( 123 ValueAnimator.RESTART); 124 startAnimation(mValueAnimator); 125 assertEquals(ValueAnimator.RESTART, mValueAnimator.getRepeatMode()); 126 } 127 128 @Test testRepeatCount()129 public void testRepeatCount() throws Throwable { 130 int repeatCount = 2; 131 ValueAnimator mValueAnimator = mActivity.createAnimatorWithRepeatCount(repeatCount); 132 startAnimation(mValueAnimator); 133 assertEquals(repeatCount, mValueAnimator.getRepeatCount()); 134 } 135 136 @Test testStartDelay()137 public void testStartDelay() { 138 long startDelay = 1000; 139 mValueAnimator.setStartDelay(startDelay); 140 assertEquals(startDelay, mValueAnimator.getStartDelay()); 141 } 142 143 /** 144 * Verify that an animator with start delay will have its listener's onAnimationStart(...) 145 * and onAnimationEnd(...) called at the right time. 146 */ 147 @Test testListenerCallbackWithStartDelay()148 public void testListenerCallbackWithStartDelay() throws Throwable { 149 final ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f); 150 anim.setStartDelay(300); 151 anim.setDuration(300); 152 AnimatorListener listener = mock(AnimatorListenerAdapter.class); 153 anim.addListener(listener); 154 mActivityRule.runOnUiThread(() -> { 155 anim.start(); 156 }); 157 158 verify(listener, timeout(450).times(1)).onAnimationStart(anim, false); 159 verify(listener, timeout(450).times(1)).onAnimationEnd(anim, false); 160 } 161 162 @Test testGetCurrentPlayTime()163 public void testGetCurrentPlayTime() throws Throwable { 164 startAnimation(mValueAnimator); 165 SystemClock.sleep(100); 166 long currentPlayTime = mValueAnimator.getCurrentPlayTime(); 167 assertTrue(currentPlayTime > 0); 168 } 169 170 @Test testSetCurrentPlayTime()171 public void testSetCurrentPlayTime() throws Throwable { 172 final ValueAnimator anim = ValueAnimator.ofFloat(0, 100).setDuration(mDuration); 173 final ValueAnimator delayedAnim = ValueAnimator.ofFloat(0, 100).setDuration(mDuration); 174 delayedAnim.setStartDelay(mDuration); 175 final long proposedCurrentPlayTime = mDuration / 2; 176 mActivityRule.runOnUiThread(() -> { 177 anim.setCurrentPlayTime(mDuration / 2); 178 long currentPlayTime = anim.getCurrentPlayTime(); 179 float currentFraction = anim.getAnimatedFraction(); 180 float currentValue = (Float) anim.getAnimatedValue(); 181 assertEquals(proposedCurrentPlayTime, currentPlayTime); 182 assertEquals(.5f, currentFraction, EPSILON); 183 assertEquals(50, currentValue, EPSILON); 184 185 delayedAnim.setCurrentPlayTime(mDuration / 2); 186 currentPlayTime = delayedAnim.getCurrentPlayTime(); 187 currentFraction = delayedAnim.getAnimatedFraction(); 188 currentValue = (Float) delayedAnim.getAnimatedValue(); 189 assertEquals(proposedCurrentPlayTime, currentPlayTime); 190 assertEquals(.5f, currentFraction, EPSILON); 191 assertEquals(50, currentValue, EPSILON); 192 }); 193 // Now make sure that it's still true a little later, to test that we're 194 // getting a result based on the seek time, not the wall clock time 195 SystemClock.sleep(100); 196 long currentPlayTime = anim.getCurrentPlayTime(); 197 float currentFraction = anim.getAnimatedFraction(); 198 float currentValue = (Float) anim.getAnimatedValue(); 199 assertEquals(proposedCurrentPlayTime, currentPlayTime); 200 assertEquals(.5f, currentFraction, EPSILON); 201 assertEquals(50, currentValue, EPSILON); 202 203 currentPlayTime = delayedAnim.getCurrentPlayTime(); 204 currentFraction = delayedAnim.getAnimatedFraction(); 205 currentValue = (Float) delayedAnim.getAnimatedValue(); 206 assertEquals(proposedCurrentPlayTime, currentPlayTime); 207 assertEquals(.5f, currentFraction, EPSILON); 208 assertEquals(50, currentValue, EPSILON); 209 210 // Finally, start() the delayed animation and check that the play time was 211 // not affected by playing during the delay 212 mActivityRule.runOnUiThread(() -> { 213 delayedAnim.start(); 214 assertEquals(proposedCurrentPlayTime, delayedAnim.getCurrentPlayTime()); 215 assertEquals(.5f, delayedAnim.getAnimatedFraction(), EPSILON); 216 assertEquals(50, (float) delayedAnim.getAnimatedValue(), EPSILON); 217 }); 218 219 SystemClock.sleep(100); 220 currentPlayTime = delayedAnim.getCurrentPlayTime(); 221 currentFraction = delayedAnim.getAnimatedFraction(); 222 currentValue = (Float) delayedAnim.getAnimatedValue(); 223 assertTrue(currentPlayTime > proposedCurrentPlayTime); 224 assertTrue(currentFraction > 0.5f); 225 assertTrue(currentValue > 50); 226 227 mActivityRule.runOnUiThread(delayedAnim::cancel); 228 } 229 230 @Test testPauseListener()231 public void testPauseListener() throws Throwable { 232 // Adds two pause listeners to the animator, and remove one after the animator is paused. 233 Animator.AnimatorPauseListener l1 = mock(Animator.AnimatorPauseListener.class); 234 Animator.AnimatorPauseListener l2 = mock(Animator.AnimatorPauseListener.class); 235 ValueAnimator a1 = ValueAnimator.ofFloat(0, 1f); 236 a1.addPauseListener(l1); 237 a1.addPauseListener(l2); 238 mActivityRule.runOnUiThread(() -> { 239 a1.start(); 240 a1.pause(); 241 verify(l1, times(1)).onAnimationPause(a1); 242 verify(l2, times(1)).onAnimationPause(a1); 243 a1.removePauseListener(l2); 244 a1.resume(); 245 }); 246 247 // Check that the pause listener that is removed doesn't have resume called. 248 verify(l1, times(1)).onAnimationResume(a1); 249 verify(l2, times(0)).onAnimationResume(a1); 250 } 251 252 @Test testSetCurrentPlayTimeAfterStart()253 public void testSetCurrentPlayTimeAfterStart() throws Throwable { 254 // This test sets current play time right after start() is called on a non-delayed animation 255 final long duration = 100; 256 final float seekFraction = 0.2f; 257 final CountDownLatch frameUpdateLatch = new CountDownLatch(1); 258 259 final AnimatorSetTest.MyListener myListener = new AnimatorSetTest.MyListener(); 260 final ValueAnimator anim = ValueAnimator.ofFloat(0, 1).setDuration(duration); 261 anim.setInterpolator(null); 262 final Animator.AnimatorListener listener = mock(Animator.AnimatorListener.class); 263 anim.addListener(listener); 264 anim.addListener(myListener); 265 mActivityRule.runOnUiThread(() -> { 266 anim.start(); 267 anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 268 float fractionOnFirstFrame = -1f; 269 270 @Override 271 public void onAnimationUpdate(ValueAnimator animation) { 272 if (fractionOnFirstFrame < 0) { 273 // First frame: 274 fractionOnFirstFrame = animation.getAnimatedFraction(); 275 assertEquals(seekFraction, fractionOnFirstFrame, EPSILON); 276 frameUpdateLatch.countDown(); 277 } else { 278 assertTrue(animation.getAnimatedFraction() >= fractionOnFirstFrame); 279 } 280 } 281 }); 282 long currentPlayTime = (long) (seekFraction * (float) duration); 283 anim.setCurrentPlayTime(currentPlayTime); 284 }); 285 assertTrue(frameUpdateLatch.await(100, TimeUnit.MILLISECONDS)); 286 verify(listener, within(200)).onAnimationEnd(anim, false); 287 // Also make sure the onAnimationEnd(anim) is called. 288 assertTrue(myListener.mEndIsCalled); 289 } 290 291 @Test testSetCurrentFraction()292 public void testSetCurrentFraction() throws Throwable { 293 final ValueAnimator anim = ValueAnimator.ofFloat(0, 100).setDuration(mDuration); 294 final long proposedCurrentPlayTime = mDuration / 2; 295 mActivityRule.runOnUiThread(() -> { 296 anim.setCurrentFraction(.5f); 297 long currentPlayTime = anim.getCurrentPlayTime(); 298 float currentFraction = anim.getAnimatedFraction(); 299 float currentValue = (Float) anim.getAnimatedValue(); 300 assertEquals(proposedCurrentPlayTime, currentPlayTime); 301 assertEquals(.5f, currentFraction, EPSILON); 302 assertEquals(50, currentValue, EPSILON); 303 }); 304 // Now make sure that it's still true a little later, to test that we're 305 // getting a result based on the seek time, not the wall clock time 306 SystemClock.sleep(100); 307 long currentPlayTime = anim.getCurrentPlayTime(); 308 float currentFraction = anim.getAnimatedFraction(); 309 float currentValue = (Float) anim.getAnimatedValue(); 310 assertEquals(proposedCurrentPlayTime, currentPlayTime); 311 assertEquals(.5f, currentFraction, EPSILON); 312 assertEquals(50, currentValue, EPSILON); 313 } 314 315 @UiThreadTest 316 @Test testReverseRightAfterStart()317 public void testReverseRightAfterStart() { 318 // Reverse() right after start() should trigger immediate end() at fraction 0. 319 final ValueAnimator anim = ValueAnimator.ofFloat(0, 100).setDuration(mDuration); 320 anim.start(); 321 assertTrue(anim.isStarted()); 322 anim.reverse(); 323 assertFalse(anim.isStarted()); 324 assertEquals(0f, anim.getAnimatedFraction(), 0.0f); 325 } 326 327 @Test testGetFrameDelay()328 public void testGetFrameDelay() throws Throwable { 329 final long frameDelay = 10; 330 mActivityRule.runOnUiThread(() -> mValueAnimator.setFrameDelay(frameDelay)); 331 startAnimation(mValueAnimator); 332 SystemClock.sleep(100); 333 mActivityRule.runOnUiThread(() -> { 334 long actualFrameDelay = mValueAnimator.getFrameDelay(); 335 assertEquals(frameDelay, actualFrameDelay); 336 }); 337 } 338 339 @Test testUpdateListeners()340 public void testUpdateListeners() throws Throwable { 341 final AnimatorSetTest.MyListener myListener = new AnimatorSetTest.MyListener(); 342 ValueAnimator.AnimatorUpdateListener l1 = mock(ValueAnimator.AnimatorUpdateListener.class); 343 ValueAnimator.AnimatorUpdateListener l2 = mock(ValueAnimator.AnimatorUpdateListener.class); 344 ValueAnimator.AnimatorUpdateListener l3 = mock(ValueAnimator.AnimatorUpdateListener.class); 345 ValueAnimator.AnimatorUpdateListener l4 = mock(ValueAnimator.AnimatorUpdateListener.class); 346 347 AnimatorListenerAdapter listener = mock(AnimatorListenerAdapter.class); 348 349 ValueAnimator a1 = ValueAnimator.ofFloat(0, 1f); 350 a1.setDuration(50); 351 a1.addUpdateListener(l1); 352 a1.addUpdateListener(l2); 353 a1.removeAllUpdateListeners(); 354 355 a1.addUpdateListener(l3); 356 a1.addUpdateListener(l4); 357 a1.removeUpdateListener(l3); 358 359 a1.addListener(listener); 360 a1.addListener(myListener); 361 362 mActivityRule.runOnUiThread(() -> { 363 a1.start(); 364 }); 365 366 // Wait for the anim to finish. 367 verify(listener, within(200)).onAnimationEnd(a1, false); 368 // Also make sure the onAnimationEnd(anim) is called. 369 assertTrue(myListener.mEndIsCalled); 370 371 verify(l1, times(0)).onAnimationUpdate(a1); 372 verify(l2, times(0)).onAnimationUpdate(a1); 373 verify(l3, times(0)).onAnimationUpdate(a1); 374 verify(l4, atLeast(1)).onAnimationUpdate(a1); 375 } 376 377 @Test testValuesSetterAndGetter()378 public void testValuesSetterAndGetter() throws Throwable { 379 380 final AnimatorSetTest.MyListener myListener = new AnimatorSetTest.MyListener(); 381 ValueAnimator a2 = ValueAnimator.ofPropertyValuesHolder(); 382 PropertyValuesHolder p1 = PropertyValuesHolder.ofFloat("scaleX", 0f, 1f); 383 PropertyValuesHolder p2 = PropertyValuesHolder.ofFloat("scaleY", 1f, 2f); 384 a2.setValues(p1, p2); 385 PropertyValuesHolder[] holders = a2.getValues(); 386 assertEquals(2, holders.length); 387 388 // Use the PropertyValueHolders returned from the getter to initialize the animator, in 389 // order to test the getter. 390 ValueAnimator a1 = ValueAnimator.ofPropertyValuesHolder(holders); 391 a1.setDuration(50); 392 a1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 393 @Override 394 public void onAnimationUpdate(ValueAnimator animation) { 395 float scaleX = (Float) animation.getAnimatedValue("scaleX"); 396 float scaleY = (Float) animation.getAnimatedValue("scaleY"); 397 assertTrue(scaleX >= 0f && scaleX <= 1f); 398 assertTrue(scaleY >= 1f && scaleY <= 2f); 399 } 400 }); 401 AnimatorListenerAdapter l1 = mock(AnimatorListenerAdapter.class); 402 a1.addListener(l1); 403 a1.addListener(myListener); 404 405 mActivityRule.runOnUiThread(() -> { 406 a1.start(); 407 }); 408 409 verify(l1, within(200)).onAnimationEnd(a1, false); 410 // Also make sure the onAnimationEnd(anim) is called. 411 assertTrue(myListener.mEndIsCalled); 412 } 413 414 @Test testSetObjectValues()415 public void testSetObjectValues() throws Throwable { 416 TypeEvaluator<PointF> eval = new TypeEvaluator<PointF>() { 417 PointF tmpValue = new PointF(); 418 @Override 419 public PointF evaluate(float fraction, PointF startValue, PointF endValue) { 420 tmpValue.x = fraction * startValue.x + (1f - fraction) * endValue.x; 421 tmpValue.y = fraction * startValue.y + (1f - fraction) * endValue.y; 422 return tmpValue; 423 } 424 }; 425 426 final AnimatorSetTest.MyListener myListener = new AnimatorSetTest.MyListener(); 427 ValueAnimator a1 = new ValueAnimator(); 428 a1.setDuration(50); 429 a1.setObjectValues(new PointF(0, 0), new PointF(1, 1)); 430 a1.setEvaluator(eval); 431 a1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 432 @Override 433 public void onAnimationUpdate(ValueAnimator animation) { 434 PointF point = (PointF) animation.getAnimatedValue(); 435 assertTrue(point.x >= 0f && point.x <= 1f); 436 assertTrue(point.y >= 0f && point.y <= 1f); 437 } 438 }); 439 AnimatorListenerAdapter l1 = mock(AnimatorListenerAdapter.class); 440 a1.addListener(l1); 441 a1.addListener(myListener); 442 mActivityRule.runOnUiThread(() -> { 443 a1.start(); 444 }); 445 446 verify(l1, within(200)).onAnimationEnd(a1, false); 447 // Also make sure the onAnimationEnd(anim) is called. 448 assertTrue(myListener.mEndIsCalled); 449 } 450 451 @Test testSetInterpolator()452 public void testSetInterpolator() throws Throwable { 453 AccelerateInterpolator interpolator = new AccelerateInterpolator(); 454 ValueAnimator mValueAnimator = mActivity.createAnimatorWithInterpolator(interpolator); 455 startAnimation(mValueAnimator); 456 assertTrue(interpolator.equals(mValueAnimator.getInterpolator())); 457 } 458 459 @Test testCancel()460 public void testCancel() throws Throwable { 461 startAnimation(mValueAnimator); 462 SystemClock.sleep(100); 463 cancelAnimation(mValueAnimator); 464 assertFalse(mValueAnimator.isRunning()); 465 } 466 467 @Test testEnd()468 public void testEnd() throws Throwable { 469 Object object = mActivity.view.newBall; 470 String property = "y"; 471 float startY = mActivity.mStartY; 472 float endY = mActivity.mStartY + mActivity.mDeltaY; 473 ObjectAnimator objAnimator = ObjectAnimator.ofFloat(object, property, startY, endY); 474 objAnimator.setDuration(mDuration); 475 objAnimator.setRepeatCount(ValueAnimator.INFINITE); 476 objAnimator.setInterpolator(new AccelerateInterpolator()); 477 objAnimator.setRepeatMode(ValueAnimator.REVERSE); 478 startAnimation(objAnimator); 479 SystemClock.sleep(100); 480 endAnimation(objAnimator); 481 float y = mActivity.view.newBall.getY(); 482 assertEquals(y, endY, 0.0f); 483 } 484 485 @Test testGetAnimatedFraction()486 public void testGetAnimatedFraction() throws Throwable { 487 ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f); 488 assertNotNull(animator); 489 animator.setDuration(200); 490 animator.addUpdateListener(new AnimatorUpdateListener() { 491 public float lastFraction = 0; 492 @Override 493 public void onAnimationUpdate(ValueAnimator animation) { 494 float currentFraction = animation.getAnimatedFraction(); 495 assertTrue( 496 "Last fraction = " + lastFraction + "current fraction = " + currentFraction, 497 animation.getAnimatedFraction() >= lastFraction); 498 lastFraction = currentFraction; 499 assertTrue(currentFraction <= 1f); 500 } 501 }); 502 CountDownLatch latch = new CountDownLatch(1); 503 animator.addListener(new AnimatorListenerAdapter() { 504 @Override 505 public void onAnimationEnd(Animator animation) { 506 latch.countDown(); 507 } 508 }); 509 mActivityRule.runOnUiThread(() -> { 510 animator.start(); 511 }); 512 513 latch.await(1000, TimeUnit.MILLISECONDS); 514 515 assertEquals(1.0f, animator.getAnimatedFraction(), EPSILON); 516 } 517 518 class TestInterpolator implements TimeInterpolator { 519 520 @Override getInterpolation(float input)521 public float getInterpolation(float input) { 522 return input * input; 523 } 524 } 525 526 @Test testGetAnimatedValue()527 public void testGetAnimatedValue() { 528 ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f); 529 assertNotNull(animator); 530 TimeInterpolator myInterpolator = new TestInterpolator(); 531 animator.setInterpolator(myInterpolator); 532 int sliceNum = 10; 533 for (int i = 0; i <= sliceNum; i++) { 534 float fraction = i / (float) sliceNum; 535 animator.setCurrentFraction(fraction); 536 assertEquals(myInterpolator.getInterpolation(fraction), 537 (float) animator.getAnimatedValue(), EPSILON); 538 539 } 540 } 541 542 @Test testGetAnimatedValue_PropertyName()543 public void testGetAnimatedValue_PropertyName() { 544 PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 100f, -100f); 545 PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 0f, 1f); 546 ValueAnimator animator = ValueAnimator.ofPropertyValuesHolder(pvhX, pvhY); 547 assertNotNull(animator); 548 TimeInterpolator myInterpolator = new TestInterpolator(); 549 animator.setInterpolator(myInterpolator); 550 int sliceNum = 10; 551 for (int i = 0; i <= sliceNum; i++) { 552 float fraction = i / (float) sliceNum; 553 animator.setCurrentFraction(fraction); 554 assertEquals(myInterpolator.getInterpolation(fraction), 555 (float) animator.getAnimatedValue("y"), EPSILON); 556 557 } 558 } 559 560 @Test testOfFloat()561 public void testOfFloat() throws Throwable { 562 float start = 0.0f; 563 float end = 1.0f; 564 float[] values = {start, end}; 565 final ValueAnimator valueAnimatorLocal = ValueAnimator.ofFloat(values); 566 valueAnimatorLocal.setDuration(mDuration); 567 valueAnimatorLocal.setRepeatCount(ValueAnimator.INFINITE); 568 valueAnimatorLocal.setInterpolator(new AccelerateInterpolator()); 569 valueAnimatorLocal.setRepeatMode(ValueAnimator.RESTART); 570 571 mActivityRule.runOnUiThread(valueAnimatorLocal::start); 572 SystemClock.sleep(100); 573 boolean isRunning = valueAnimatorLocal.isRunning(); 574 assertTrue(isRunning); 575 576 Float animatedValue = (Float) valueAnimatorLocal.getAnimatedValue(); 577 assertTrue(animatedValue >= start); 578 assertTrue(animatedValue <= end); 579 } 580 581 @Test testOfInt()582 public void testOfInt() throws Throwable { 583 int start = 0; 584 int end = 10; 585 int[] values = {start, end}; 586 final ValueAnimator valueAnimatorLocal = ValueAnimator.ofInt(values); 587 valueAnimatorLocal.setDuration(mDuration); 588 valueAnimatorLocal.setRepeatCount(ValueAnimator.INFINITE); 589 valueAnimatorLocal.setInterpolator(new AccelerateInterpolator()); 590 valueAnimatorLocal.setRepeatMode(ValueAnimator.RESTART); 591 592 mActivityRule.runOnUiThread(valueAnimatorLocal::start); 593 SystemClock.sleep(100); 594 boolean isRunning = valueAnimatorLocal.isRunning(); 595 assertTrue(isRunning); 596 597 Integer animatedValue = (Integer) valueAnimatorLocal.getAnimatedValue(); 598 assertTrue(animatedValue >= start); 599 assertTrue(animatedValue <= end); 600 } 601 602 @Test testOfArgb()603 public void testOfArgb() throws Throwable { 604 int start = 0xffff0000; 605 int end = 0xff0000ff; 606 int[] values = {start, end}; 607 int startRed = Color.red(start); 608 int startBlue = Color.blue(start); 609 int endRed = Color.red(end); 610 int endBlue = Color.blue(end); 611 final ValueAnimator valueAnimatorLocal = ValueAnimator.ofArgb(values); 612 valueAnimatorLocal.setDuration(mDuration); 613 614 final CountDownLatch latch = new CountDownLatch(1); 615 valueAnimatorLocal.addUpdateListener((ValueAnimator animation) -> { 616 if (animation.getAnimatedFraction() > .05f) { 617 latch.countDown(); 618 } 619 }); 620 621 mActivityRule.runOnUiThread(valueAnimatorLocal::start); 622 boolean isRunning = valueAnimatorLocal.isRunning(); 623 assertTrue(isRunning); 624 625 assertTrue(latch.await(500, TimeUnit.MILLISECONDS)); 626 627 Integer animatedValue = (Integer) valueAnimatorLocal.getAnimatedValue(); 628 int alpha = Color.alpha(animatedValue); 629 int red = Color.red(animatedValue); 630 int green = Color.green(animatedValue); 631 int blue = Color.blue(animatedValue); 632 assertTrue(red < startRed); 633 assertTrue(red > endRed); 634 assertTrue(blue > startBlue); 635 assertTrue(blue < endBlue); 636 assertEquals(255, alpha); 637 assertEquals(0, green); 638 639 mActivityRule.runOnUiThread(valueAnimatorLocal::cancel); 640 } 641 642 @Test 643 public void testNoDelayOnSeekAnimation() throws Throwable { 644 ValueAnimator animator = ValueAnimator.ofFloat(0, 1); 645 animator.setInterpolator(new LinearInterpolator()); 646 animator.setStartDelay(1000); 647 animator.setDuration(300); 648 animator.setCurrentPlayTime(150); 649 final Animator.AnimatorListener watcher = mock(Animator.AnimatorListener.class); 650 animator.addListener(watcher); 651 mActivityRule.runOnUiThread(animator::start); 652 verify(watcher, times(1)).onAnimationStart(animator, false); 653 assertTrue(((Float)animator.getAnimatedValue()) >= 0.5f); 654 assertTrue(animator.getAnimatedFraction() >= 0.5f); 655 mActivityRule.runOnUiThread(animator::cancel); 656 } 657 658 @Test testNotifiesAfterEnd()659 public void testNotifiesAfterEnd() throws Throwable { 660 final ValueAnimator animator = ValueAnimator.ofFloat(0, 1); 661 animator.addListener(new AnimatorListenerAdapter() { 662 @Override 663 public void onAnimationStart(Animator animation) { 664 assertTrue(animation.isStarted()); 665 assertTrue(animation.isRunning()); 666 } 667 668 @Override 669 public void onAnimationEnd(Animator animation) { 670 assertFalse(animation.isRunning()); 671 assertFalse(animation.isStarted()); 672 super.onAnimationEnd(animation); 673 } 674 }); 675 mActivityRule.runOnUiThread(() -> { 676 animator.start(); 677 animator.end(); 678 }); 679 } 680 681 @Test testAnimatorsEnabled()682 public void testAnimatorsEnabled() throws Throwable { 683 float currentDurationScale = ValueAnimator.getDurationScale(); 684 try { 685 testAnimatorsEnabledImpl(true); 686 testAnimatorsEnabledImpl(false); 687 } finally { 688 // restore scale value to avoid messing up future tests 689 ValueAnimator.setDurationScale(currentDurationScale); 690 } 691 } 692 693 @Test testAnimationDurationNoShortenByTinkeredScale()694 public void testAnimationDurationNoShortenByTinkeredScale() throws Throwable { 695 final long expectedDurationMs = 1000L; 696 final long minDurationMs = expectedDurationMs; 697 final long maxDurationMs = expectedDurationMs + 200L; 698 final Range<Long> durationRange = new Range<>(minDurationMs, maxDurationMs); 699 700 final CountDownLatch endLatch = new CountDownLatch(1); 701 long[] startAnimationTime = new long[1]; 702 long[] endAnimationTime = new long[1]; 703 704 final float durationScale = 1.0f; 705 float currentDurationScale = ValueAnimator.getDurationScale(); 706 try { 707 ValueAnimator.setDurationScale(durationScale); 708 assertTrue("The duration scale of ValueAnimator should be 1.0f," 709 + " actual=" + ValueAnimator.getDurationScale(), 710 ValueAnimator.getDurationScale() == durationScale); 711 712 ValueAnimator animator = ValueAnimator.ofFloat(0, 1); 713 animator.setInterpolator(new LinearInterpolator()); 714 animator.setDuration(expectedDurationMs); 715 assertEquals(animator.getDuration(), expectedDurationMs); 716 717 animator.addListener(new AnimatorListenerAdapter() { 718 @Override 719 public void onAnimationEnd(Animator animation) { 720 endAnimationTime[0] = SystemClock.uptimeMillis(); 721 endLatch.countDown(); 722 } 723 }); 724 725 // Start the animation and verify if the actual animation duration is in the range. 726 mActivityRule.runOnUiThread(() -> { 727 startAnimationTime[0] = SystemClock.uptimeMillis(); 728 animator.start(); 729 }); 730 endLatch.await(2, TimeUnit.SECONDS); 731 final long totalTime = endAnimationTime[0] - startAnimationTime[0]; 732 assertTrue("ValueAnimator the duration should be in the range " 733 + "<" + minDurationMs + ", " + maxDurationMs + "> ms, " 734 + "actual=" + totalTime, durationRange.contains(totalTime)); 735 } finally { 736 // restore scale value to avoid messing up future tests 737 ValueAnimator.setDurationScale(currentDurationScale); 738 } 739 } 740 testAnimatorsEnabledImpl(boolean enabled)741 private void testAnimatorsEnabledImpl(boolean enabled) throws Throwable { 742 final CountDownLatch startLatch = new CountDownLatch(1); 743 final CountDownLatch endLatch = new CountDownLatch(1); 744 final ValueAnimator animator = ValueAnimator.ofFloat(0, 1); 745 746 animator.setDuration(1000); 747 animator.addListener(new AnimatorListenerAdapter() { 748 @Override 749 public void onAnimationEnd(Animator animation) { 750 endLatch.countDown(); 751 } 752 }); 753 mActivityRule.runOnUiThread(() -> { 754 animator.start(); 755 startLatch.countDown(); 756 }); 757 758 assertTrue(startLatch.await(200, TimeUnit.MILLISECONDS)); 759 760 float durationScale = enabled ? 1 : 0; 761 ValueAnimator.setDurationScale(durationScale); 762 763 if (enabled) { 764 assertTrue("Animators not enabled with duration scale 1", 765 ValueAnimator.areAnimatorsEnabled()); 766 assertFalse("Animator ended too early when animators enabled = ", 767 endLatch.await(100, TimeUnit.MILLISECONDS)); 768 } else { 769 assertFalse("Animators enabled with duration scale 0", 770 ValueAnimator.areAnimatorsEnabled()); 771 assertTrue("Animator did not end when animators enabled = ", 772 endLatch.await(100, TimeUnit.MILLISECONDS)); 773 } 774 mActivityRule.runOnUiThread(() -> { 775 animator.end(); 776 }); 777 } 778 getAnimator()779 private ValueAnimator getAnimator() { 780 Object object = mActivity.view.newBall; 781 String property = "y"; 782 float startY = mActivity.mStartY; 783 float endY = mActivity.mStartY + mActivity.mDeltaY; 784 ValueAnimator objAnimator = ObjectAnimator.ofFloat(object, property, startY, endY); 785 objAnimator.setDuration(mDuration); 786 objAnimator.setRepeatCount(ValueAnimator.INFINITE); 787 objAnimator.setInterpolator(new AccelerateInterpolator()); 788 objAnimator.setRepeatMode(ValueAnimator.REVERSE); 789 return objAnimator; 790 } 791 startAnimation(final ValueAnimator animator)792 private void startAnimation(final ValueAnimator animator) throws Throwable { 793 mActivityRule.runOnUiThread(() -> mActivity.startAnimation(animator)); 794 } 795 endAnimation(final ValueAnimator animator)796 private void endAnimation(final ValueAnimator animator) throws Throwable { 797 mActivityRule.runOnUiThread(animator::end); 798 } 799 cancelAnimation(final ValueAnimator animator)800 private void cancelAnimation(final ValueAnimator animator) throws Throwable { 801 mActivityRule.runOnUiThread(animator::cancel); 802 } 803 errorMessage(float[] values)804 private String errorMessage(float[] values) { 805 StringBuilder message = new StringBuilder(); 806 for (int i = 0; i < values.length; i++) { 807 message.append(values[i]).append(" "); 808 } 809 return message.toString(); 810 } 811 } 812