1 /* 2 * Copyright (C) 2010 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.animation; 18 19 import android.annotation.CallSuper; 20 import android.annotation.IntDef; 21 import android.annotation.Nullable; 22 import android.annotation.TestApi; 23 import android.compat.annotation.UnsupportedAppUsage; 24 import android.os.Build; 25 import android.os.Looper; 26 import android.os.Trace; 27 import android.util.AndroidRuntimeException; 28 import android.util.Log; 29 import android.view.animation.AccelerateDecelerateInterpolator; 30 import android.view.animation.Animation; 31 import android.view.animation.AnimationUtils; 32 import android.view.animation.LinearInterpolator; 33 34 import java.lang.annotation.Retention; 35 import java.lang.annotation.RetentionPolicy; 36 import java.util.ArrayList; 37 import java.util.HashMap; 38 39 /** 40 * This class provides a simple timing engine for running animations 41 * which calculate animated values and set them on target objects. 42 * 43 * <p>There is a single timing pulse that all animations use. It runs in a 44 * custom handler to ensure that property changes happen on the UI thread.</p> 45 * 46 * <p>By default, ValueAnimator uses non-linear time interpolation, via the 47 * {@link AccelerateDecelerateInterpolator} class, which accelerates into and decelerates 48 * out of an animation. This behavior can be changed by calling 49 * {@link ValueAnimator#setInterpolator(TimeInterpolator)}.</p> 50 * 51 * <p>Animators can be created from either code or resource files. Here is an example 52 * of a ValueAnimator resource file:</p> 53 * 54 * {@sample development/samples/ApiDemos/res/anim/animator.xml ValueAnimatorResources} 55 * 56 * <p>Starting from API 23, it is also possible to use a combination of {@link PropertyValuesHolder} 57 * and {@link Keyframe} resource tags to create a multi-step animation. 58 * Note that you can specify explicit fractional values (from 0 to 1) for 59 * each keyframe to determine when, in the overall duration, the animation should arrive at that 60 * value. Alternatively, you can leave the fractions off and the keyframes will be equally 61 * distributed within the total duration:</p> 62 * 63 * {@sample development/samples/ApiDemos/res/anim/value_animator_pvh_kf.xml 64 * ValueAnimatorKeyframeResources} 65 * 66 * <div class="special reference"> 67 * <h3>Developer Guides</h3> 68 * <p>For more information about animating with {@code ValueAnimator}, read the 69 * <a href="{@docRoot}guide/topics/graphics/prop-animation.html#value-animator">Property 70 * Animation</a> developer guide.</p> 71 * </div> 72 */ 73 @SuppressWarnings("unchecked") 74 public class ValueAnimator extends Animator implements AnimationHandler.AnimationFrameCallback { 75 private static final String TAG = "ValueAnimator"; 76 private static final boolean DEBUG = false; 77 78 /** 79 * Internal constants 80 */ 81 82 /** 83 * System-wide animation scale. 84 * 85 * <p>To check whether animations are enabled system-wise use {@link #areAnimatorsEnabled()}. 86 */ 87 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 88 private static float sDurationScale = 1.0f; 89 90 /** 91 * Internal variables 92 * NOTE: This object implements the clone() method, making a deep copy of any referenced 93 * objects. As other non-trivial fields are added to this class, make sure to add logic 94 * to clone() to make deep copies of them. 95 */ 96 97 /** 98 * The first time that the animation's animateFrame() method is called. This time is used to 99 * determine elapsed time (and therefore the elapsed fraction) in subsequent calls 100 * to animateFrame(). 101 * 102 * Whenever mStartTime is set, you must also update mStartTimeCommitted. 103 */ 104 long mStartTime = -1; 105 106 /** 107 * When true, the start time has been firmly committed as a chosen reference point in 108 * time by which the progress of the animation will be evaluated. When false, the 109 * start time may be updated when the first animation frame is committed so as 110 * to compensate for jank that may have occurred between when the start time was 111 * initialized and when the frame was actually drawn. 112 * 113 * This flag is generally set to false during the first frame of the animation 114 * when the animation playing state transitions from STOPPED to RUNNING or 115 * resumes after having been paused. This flag is set to true when the start time 116 * is firmly committed and should not be further compensated for jank. 117 */ 118 boolean mStartTimeCommitted; 119 120 /** 121 * Set when setCurrentPlayTime() is called. If negative, animation is not currently seeked 122 * to a value. 123 */ 124 float mSeekFraction = -1; 125 126 /** 127 * Set on the next frame after pause() is called, used to calculate a new startTime 128 * or delayStartTime which allows the animator to continue from the point at which 129 * it was paused. If negative, has not yet been set. 130 */ 131 private long mPauseTime; 132 133 /** 134 * Set when an animator is resumed. This triggers logic in the next frame which 135 * actually resumes the animator. 136 */ 137 private boolean mResumed = false; 138 139 // The time interpolator to be used if none is set on the animation 140 private static final TimeInterpolator sDefaultInterpolator = 141 new AccelerateDecelerateInterpolator(); 142 143 /** 144 * Flag to indicate whether this animator is playing in reverse mode, specifically 145 * by being started or interrupted by a call to reverse(). This flag is different than 146 * mPlayingBackwards, which indicates merely whether the current iteration of the 147 * animator is playing in reverse. It is used in corner cases to determine proper end 148 * behavior. 149 */ 150 private boolean mReversing; 151 152 /** 153 * Tracks the overall fraction of the animation, ranging from 0 to mRepeatCount + 1 154 */ 155 private float mOverallFraction = 0f; 156 157 /** 158 * Tracks current elapsed/eased fraction, for querying in getAnimatedFraction(). 159 * This is calculated by interpolating the fraction (range: [0, 1]) in the current iteration. 160 */ 161 private float mCurrentFraction = 0f; 162 163 /** 164 * Tracks the time (in milliseconds) when the last frame arrived. 165 */ 166 private long mLastFrameTime = -1; 167 168 /** 169 * Tracks the time (in milliseconds) when the first frame arrived. Note the frame may arrive 170 * during the start delay. 171 */ 172 private long mFirstFrameTime = -1; 173 174 /** 175 * Additional playing state to indicate whether an animator has been start()'d. There is 176 * some lag between a call to start() and the first animation frame. We should still note 177 * that the animation has been started, even if it's first animation frame has not yet 178 * happened, and reflect that state in isRunning(). 179 * Note that delayed animations are different: they are not started until their first 180 * animation frame, which occurs after their delay elapses. 181 */ 182 private boolean mRunning = false; 183 184 /** 185 * Additional playing state to indicate whether an animator has been start()'d, whether or 186 * not there is a nonzero startDelay. 187 */ 188 private boolean mStarted = false; 189 190 /** 191 * Tracks whether we've notified listeners of the onAnimationStart() event. This can be 192 * complex to keep track of since we notify listeners at different times depending on 193 * startDelay and whether start() was called before end(). 194 */ 195 private boolean mStartListenersCalled = false; 196 197 /** 198 * Flag that denotes whether the animation is set up and ready to go. Used to 199 * set up animation that has not yet been started. 200 */ 201 boolean mInitialized = false; 202 203 /** 204 * Flag that tracks whether animation has been requested to end. 205 */ 206 private boolean mAnimationEndRequested = false; 207 208 // 209 // Backing variables 210 // 211 212 // How long the animation should last in ms 213 @UnsupportedAppUsage 214 private long mDuration = 300; 215 216 // The amount of time in ms to delay starting the animation after start() is called. Note 217 // that this start delay is unscaled. When there is a duration scale set on the animator, the 218 // scaling factor will be applied to this delay. 219 private long mStartDelay = 0; 220 221 // The number of times the animation will repeat. The default is 0, which means the animation 222 // will play only once 223 private int mRepeatCount = 0; 224 225 /** 226 * The type of repetition that will occur when repeatMode is nonzero. RESTART means the 227 * animation will start from the beginning on every new cycle. REVERSE means the animation 228 * will reverse directions on each iteration. 229 */ 230 private int mRepeatMode = RESTART; 231 232 /** 233 * Whether or not the animator should register for its own animation callback to receive 234 * animation pulse. 235 */ 236 private boolean mSelfPulse = true; 237 238 /** 239 * Whether or not the animator has been requested to start without pulsing. This flag gets set 240 * in startWithoutPulsing(), and reset in start(). 241 */ 242 private boolean mSuppressSelfPulseRequested = false; 243 244 /** 245 * The time interpolator to be used. The elapsed fraction of the animation will be passed 246 * through this interpolator to calculate the interpolated fraction, which is then used to 247 * calculate the animated values. 248 */ 249 private TimeInterpolator mInterpolator = sDefaultInterpolator; 250 251 /** 252 * The set of listeners to be sent events through the life of an animation. 253 */ 254 ArrayList<AnimatorUpdateListener> mUpdateListeners = null; 255 256 /** 257 * The property/value sets being animated. 258 */ 259 PropertyValuesHolder[] mValues; 260 261 /** 262 * A hashmap of the PropertyValuesHolder objects. This map is used to lookup animated values 263 * by property name during calls to getAnimatedValue(String). 264 */ 265 HashMap<String, PropertyValuesHolder> mValuesMap; 266 267 /** 268 * If set to non-negative value, this will override {@link #sDurationScale}. 269 */ 270 private float mDurationScale = -1f; 271 272 /** 273 * Animation handler used to schedule updates for this animation. 274 */ 275 private AnimationHandler mAnimationHandler; 276 277 /** 278 * Public constants 279 */ 280 281 /** @hide */ 282 @IntDef({RESTART, REVERSE}) 283 @Retention(RetentionPolicy.SOURCE) 284 public @interface RepeatMode {} 285 286 /** 287 * When the animation reaches the end and <code>repeatCount</code> is INFINITE 288 * or a positive value, the animation restarts from the beginning. 289 */ 290 public static final int RESTART = 1; 291 /** 292 * When the animation reaches the end and <code>repeatCount</code> is INFINITE 293 * or a positive value, the animation reverses direction on every iteration. 294 */ 295 public static final int REVERSE = 2; 296 /** 297 * This value used used with the {@link #setRepeatCount(int)} property to repeat 298 * the animation indefinitely. 299 */ 300 public static final int INFINITE = -1; 301 302 /** 303 * @hide 304 */ 305 @UnsupportedAppUsage 306 @TestApi setDurationScale(float durationScale)307 public static void setDurationScale(float durationScale) { 308 sDurationScale = durationScale; 309 } 310 311 /** 312 * @hide 313 */ 314 @UnsupportedAppUsage 315 @TestApi getDurationScale()316 public static float getDurationScale() { 317 return sDurationScale; 318 } 319 320 /** 321 * Returns whether animators are currently enabled, system-wide. By default, all 322 * animators are enabled. This can change if either the user sets a Developer Option 323 * to set the animator duration scale to 0 or by Battery Savery mode being enabled 324 * (which disables all animations). 325 * 326 * <p>Developers should not typically need to call this method, but should an app wish 327 * to show a different experience when animators are disabled, this return value 328 * can be used as a decider of which experience to offer. 329 * 330 * @return boolean Whether animators are currently enabled. The default value is 331 * <code>true</code>. 332 */ areAnimatorsEnabled()333 public static boolean areAnimatorsEnabled() { 334 return !(sDurationScale == 0); 335 } 336 337 /** 338 * Creates a new ValueAnimator object. This default constructor is primarily for 339 * use internally; the factory methods which take parameters are more generally 340 * useful. 341 */ ValueAnimator()342 public ValueAnimator() { 343 } 344 345 /** 346 * Constructs and returns a ValueAnimator that animates between int values. A single 347 * value implies that that value is the one being animated to. However, this is not typically 348 * useful in a ValueAnimator object because there is no way for the object to determine the 349 * starting value for the animation (unlike ObjectAnimator, which can derive that value 350 * from the target object and property being animated). Therefore, there should typically 351 * be two or more values. 352 * 353 * @param values A set of values that the animation will animate between over time. 354 * @return A ValueAnimator object that is set up to animate between the given values. 355 */ ofInt(int... values)356 public static ValueAnimator ofInt(int... values) { 357 ValueAnimator anim = new ValueAnimator(); 358 anim.setIntValues(values); 359 return anim; 360 } 361 362 /** 363 * Constructs and returns a ValueAnimator that animates between color values. A single 364 * value implies that that value is the one being animated to. However, this is not typically 365 * useful in a ValueAnimator object because there is no way for the object to determine the 366 * starting value for the animation (unlike ObjectAnimator, which can derive that value 367 * from the target object and property being animated). Therefore, there should typically 368 * be two or more values. 369 * 370 * @param values A set of values that the animation will animate between over time. 371 * @return A ValueAnimator object that is set up to animate between the given values. 372 */ ofArgb(int... values)373 public static ValueAnimator ofArgb(int... values) { 374 ValueAnimator anim = new ValueAnimator(); 375 anim.setIntValues(values); 376 anim.setEvaluator(ArgbEvaluator.getInstance()); 377 return anim; 378 } 379 380 /** 381 * Constructs and returns a ValueAnimator that animates between float values. A single 382 * value implies that that value is the one being animated to. However, this is not typically 383 * useful in a ValueAnimator object because there is no way for the object to determine the 384 * starting value for the animation (unlike ObjectAnimator, which can derive that value 385 * from the target object and property being animated). Therefore, there should typically 386 * be two or more values. 387 * 388 * @param values A set of values that the animation will animate between over time. 389 * @return A ValueAnimator object that is set up to animate between the given values. 390 */ ofFloat(float... values)391 public static ValueAnimator ofFloat(float... values) { 392 ValueAnimator anim = new ValueAnimator(); 393 anim.setFloatValues(values); 394 return anim; 395 } 396 397 /** 398 * Constructs and returns a ValueAnimator that animates between the values 399 * specified in the PropertyValuesHolder objects. 400 * 401 * @param values A set of PropertyValuesHolder objects whose values will be animated 402 * between over time. 403 * @return A ValueAnimator object that is set up to animate between the given values. 404 */ ofPropertyValuesHolder(PropertyValuesHolder... values)405 public static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values) { 406 ValueAnimator anim = new ValueAnimator(); 407 anim.setValues(values); 408 return anim; 409 } 410 /** 411 * Constructs and returns a ValueAnimator that animates between Object values. A single 412 * value implies that that value is the one being animated to. However, this is not typically 413 * useful in a ValueAnimator object because there is no way for the object to determine the 414 * starting value for the animation (unlike ObjectAnimator, which can derive that value 415 * from the target object and property being animated). Therefore, there should typically 416 * be two or more values. 417 * 418 * <p><strong>Note:</strong> The Object values are stored as references to the original 419 * objects, which means that changes to those objects after this method is called will 420 * affect the values on the animator. If the objects will be mutated externally after 421 * this method is called, callers should pass a copy of those objects instead. 422 * 423 * <p>Since ValueAnimator does not know how to animate between arbitrary Objects, this 424 * factory method also takes a TypeEvaluator object that the ValueAnimator will use 425 * to perform that interpolation. 426 * 427 * @param evaluator A TypeEvaluator that will be called on each animation frame to 428 * provide the ncessry interpolation between the Object values to derive the animated 429 * value. 430 * @param values A set of values that the animation will animate between over time. 431 * @return A ValueAnimator object that is set up to animate between the given values. 432 */ ofObject(TypeEvaluator evaluator, Object... values)433 public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values) { 434 ValueAnimator anim = new ValueAnimator(); 435 anim.setObjectValues(values); 436 anim.setEvaluator(evaluator); 437 return anim; 438 } 439 440 /** 441 * Sets int values that will be animated between. A single 442 * value implies that that value is the one being animated to. However, this is not typically 443 * useful in a ValueAnimator object because there is no way for the object to determine the 444 * starting value for the animation (unlike ObjectAnimator, which can derive that value 445 * from the target object and property being animated). Therefore, there should typically 446 * be two or more values. 447 * 448 * <p>If there are already multiple sets of values defined for this ValueAnimator via more 449 * than one PropertyValuesHolder object, this method will set the values for the first 450 * of those objects.</p> 451 * 452 * @param values A set of values that the animation will animate between over time. 453 */ setIntValues(int... values)454 public void setIntValues(int... values) { 455 if (values == null || values.length == 0) { 456 return; 457 } 458 if (mValues == null || mValues.length == 0) { 459 setValues(PropertyValuesHolder.ofInt("", values)); 460 } else { 461 PropertyValuesHolder valuesHolder = mValues[0]; 462 valuesHolder.setIntValues(values); 463 } 464 // New property/values/target should cause re-initialization prior to starting 465 mInitialized = false; 466 } 467 468 /** 469 * Sets float values that will be animated between. A single 470 * value implies that that value is the one being animated to. However, this is not typically 471 * useful in a ValueAnimator object because there is no way for the object to determine the 472 * starting value for the animation (unlike ObjectAnimator, which can derive that value 473 * from the target object and property being animated). Therefore, there should typically 474 * be two or more values. 475 * 476 * <p>If there are already multiple sets of values defined for this ValueAnimator via more 477 * than one PropertyValuesHolder object, this method will set the values for the first 478 * of those objects.</p> 479 * 480 * @param values A set of values that the animation will animate between over time. 481 */ setFloatValues(float... values)482 public void setFloatValues(float... values) { 483 if (values == null || values.length == 0) { 484 return; 485 } 486 if (mValues == null || mValues.length == 0) { 487 setValues(PropertyValuesHolder.ofFloat("", values)); 488 } else { 489 PropertyValuesHolder valuesHolder = mValues[0]; 490 valuesHolder.setFloatValues(values); 491 } 492 // New property/values/target should cause re-initialization prior to starting 493 mInitialized = false; 494 } 495 496 /** 497 * Sets the values to animate between for this animation. A single 498 * value implies that that value is the one being animated to. However, this is not typically 499 * useful in a ValueAnimator object because there is no way for the object to determine the 500 * starting value for the animation (unlike ObjectAnimator, which can derive that value 501 * from the target object and property being animated). Therefore, there should typically 502 * be two or more values. 503 * 504 * <p><strong>Note:</strong> The Object values are stored as references to the original 505 * objects, which means that changes to those objects after this method is called will 506 * affect the values on the animator. If the objects will be mutated externally after 507 * this method is called, callers should pass a copy of those objects instead. 508 * 509 * <p>If there are already multiple sets of values defined for this ValueAnimator via more 510 * than one PropertyValuesHolder object, this method will set the values for the first 511 * of those objects.</p> 512 * 513 * <p>There should be a TypeEvaluator set on the ValueAnimator that knows how to interpolate 514 * between these value objects. ValueAnimator only knows how to interpolate between the 515 * primitive types specified in the other setValues() methods.</p> 516 * 517 * @param values The set of values to animate between. 518 */ setObjectValues(Object... values)519 public void setObjectValues(Object... values) { 520 if (values == null || values.length == 0) { 521 return; 522 } 523 if (mValues == null || mValues.length == 0) { 524 setValues(PropertyValuesHolder.ofObject("", null, values)); 525 } else { 526 PropertyValuesHolder valuesHolder = mValues[0]; 527 valuesHolder.setObjectValues(values); 528 } 529 // New property/values/target should cause re-initialization prior to starting 530 mInitialized = false; 531 } 532 533 /** 534 * Sets the values, per property, being animated between. This function is called internally 535 * by the constructors of ValueAnimator that take a list of values. But a ValueAnimator can 536 * be constructed without values and this method can be called to set the values manually 537 * instead. 538 * 539 * @param values The set of values, per property, being animated between. 540 */ setValues(PropertyValuesHolder... values)541 public void setValues(PropertyValuesHolder... values) { 542 int numValues = values.length; 543 mValues = values; 544 mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues); 545 for (int i = 0; i < numValues; ++i) { 546 PropertyValuesHolder valuesHolder = values[i]; 547 mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder); 548 } 549 // New property/values/target should cause re-initialization prior to starting 550 mInitialized = false; 551 } 552 553 /** 554 * Returns the values that this ValueAnimator animates between. These values are stored in 555 * PropertyValuesHolder objects, even if the ValueAnimator was created with a simple list 556 * of value objects instead. 557 * 558 * @return PropertyValuesHolder[] An array of PropertyValuesHolder objects which hold the 559 * values, per property, that define the animation. 560 */ getValues()561 public PropertyValuesHolder[] getValues() { 562 return mValues; 563 } 564 565 /** 566 * This function is called immediately before processing the first animation 567 * frame of an animation. If there is a nonzero <code>startDelay</code>, the 568 * function is called after that delay ends. 569 * It takes care of the final initialization steps for the 570 * animation. 571 * 572 * <p>Overrides of this method should call the superclass method to ensure 573 * that internal mechanisms for the animation are set up correctly.</p> 574 */ 575 @CallSuper initAnimation()576 void initAnimation() { 577 if (!mInitialized) { 578 int numValues = mValues.length; 579 for (int i = 0; i < numValues; ++i) { 580 mValues[i].init(); 581 } 582 mInitialized = true; 583 } 584 } 585 586 /** 587 * Sets the length of the animation. The default duration is 300 milliseconds. 588 * 589 * @param duration The length of the animation, in milliseconds. This value cannot 590 * be negative. 591 * @return ValueAnimator The object called with setDuration(). This return 592 * value makes it easier to compose statements together that construct and then set the 593 * duration, as in <code>ValueAnimator.ofInt(0, 10).setDuration(500).start()</code>. 594 */ 595 @Override setDuration(long duration)596 public ValueAnimator setDuration(long duration) { 597 if (duration < 0) { 598 throw new IllegalArgumentException("Animators cannot have negative duration: " + 599 duration); 600 } 601 mDuration = duration; 602 return this; 603 } 604 605 /** 606 * Overrides the global duration scale by a custom value. 607 * 608 * @param durationScale The duration scale to set; or {@code -1f} to use the global duration 609 * scale. 610 * @hide 611 */ overrideDurationScale(float durationScale)612 public void overrideDurationScale(float durationScale) { 613 mDurationScale = durationScale; 614 } 615 resolveDurationScale()616 private float resolveDurationScale() { 617 return mDurationScale >= 0f ? mDurationScale : sDurationScale; 618 } 619 getScaledDuration()620 private long getScaledDuration() { 621 return (long)(mDuration * resolveDurationScale()); 622 } 623 624 /** 625 * Gets the length of the animation. The default duration is 300 milliseconds. 626 * 627 * @return The length of the animation, in milliseconds. 628 */ 629 @Override getDuration()630 public long getDuration() { 631 return mDuration; 632 } 633 634 @Override getTotalDuration()635 public long getTotalDuration() { 636 if (mRepeatCount == INFINITE) { 637 return DURATION_INFINITE; 638 } else { 639 return mStartDelay + (mDuration * (mRepeatCount + 1)); 640 } 641 } 642 643 /** 644 * Sets the position of the animation to the specified point in time. This time should 645 * be between 0 and the total duration of the animation, including any repetition. If 646 * the animation has not yet been started, then it will not advance forward after it is 647 * set to this time; it will simply set the time to this value and perform any appropriate 648 * actions based on that time. If the animation is already running, then setCurrentPlayTime() 649 * will set the current playing time to this value and continue playing from that point. 650 * 651 * @param playTime The time, in milliseconds, to which the animation is advanced or rewound. 652 */ setCurrentPlayTime(long playTime)653 public void setCurrentPlayTime(long playTime) { 654 float fraction = mDuration > 0 ? (float) playTime / mDuration : 1; 655 setCurrentFraction(fraction); 656 } 657 658 /** 659 * Sets the position of the animation to the specified fraction. This fraction should 660 * be between 0 and the total fraction of the animation, including any repetition. That is, 661 * a fraction of 0 will position the animation at the beginning, a value of 1 at the end, 662 * and a value of 2 at the end of a reversing animator that repeats once. If 663 * the animation has not yet been started, then it will not advance forward after it is 664 * set to this fraction; it will simply set the fraction to this value and perform any 665 * appropriate actions based on that fraction. If the animation is already running, then 666 * setCurrentFraction() will set the current fraction to this value and continue 667 * playing from that point. {@link Animator.AnimatorListener} events are not called 668 * due to changing the fraction; those events are only processed while the animation 669 * is running. 670 * 671 * @param fraction The fraction to which the animation is advanced or rewound. Values 672 * outside the range of 0 to the maximum fraction for the animator will be clamped to 673 * the correct range. 674 */ setCurrentFraction(float fraction)675 public void setCurrentFraction(float fraction) { 676 initAnimation(); 677 fraction = clampFraction(fraction); 678 mStartTimeCommitted = true; // do not allow start time to be compensated for jank 679 if (isPulsingInternal()) { 680 long seekTime = (long) (getScaledDuration() * fraction); 681 long currentTime = AnimationUtils.currentAnimationTimeMillis(); 682 // Only modify the start time when the animation is running. Seek fraction will ensure 683 // non-running animations skip to the correct start time. 684 mStartTime = currentTime - seekTime; 685 } else { 686 // If the animation loop hasn't started, or during start delay, the startTime will be 687 // adjusted once the delay has passed based on seek fraction. 688 mSeekFraction = fraction; 689 } 690 mOverallFraction = fraction; 691 final float currentIterationFraction = getCurrentIterationFraction(fraction, mReversing); 692 animateValue(currentIterationFraction); 693 } 694 695 /** 696 * Calculates current iteration based on the overall fraction. The overall fraction will be 697 * in the range of [0, mRepeatCount + 1]. Both current iteration and fraction in the current 698 * iteration can be derived from it. 699 */ getCurrentIteration(float fraction)700 private int getCurrentIteration(float fraction) { 701 fraction = clampFraction(fraction); 702 // If the overall fraction is a positive integer, we consider the current iteration to be 703 // complete. In other words, the fraction for the current iteration would be 1, and the 704 // current iteration would be overall fraction - 1. 705 double iteration = Math.floor(fraction); 706 if (fraction == iteration && fraction > 0) { 707 iteration--; 708 } 709 return (int) iteration; 710 } 711 712 /** 713 * Calculates the fraction of the current iteration, taking into account whether the animation 714 * should be played backwards. E.g. When the animation is played backwards in an iteration, 715 * the fraction for that iteration will go from 1f to 0f. 716 */ getCurrentIterationFraction(float fraction, boolean inReverse)717 private float getCurrentIterationFraction(float fraction, boolean inReverse) { 718 fraction = clampFraction(fraction); 719 int iteration = getCurrentIteration(fraction); 720 float currentFraction = fraction - iteration; 721 return shouldPlayBackward(iteration, inReverse) ? 1f - currentFraction : currentFraction; 722 } 723 724 /** 725 * Clamps fraction into the correct range: [0, mRepeatCount + 1]. If repeat count is infinite, 726 * no upper bound will be set for the fraction. 727 * 728 * @param fraction fraction to be clamped 729 * @return fraction clamped into the range of [0, mRepeatCount + 1] 730 */ clampFraction(float fraction)731 private float clampFraction(float fraction) { 732 if (fraction < 0) { 733 fraction = 0; 734 } else if (mRepeatCount != INFINITE) { 735 fraction = Math.min(fraction, mRepeatCount + 1); 736 } 737 return fraction; 738 } 739 740 /** 741 * Calculates the direction of animation playing (i.e. forward or backward), based on 1) 742 * whether the entire animation is being reversed, 2) repeat mode applied to the current 743 * iteration. 744 */ shouldPlayBackward(int iteration, boolean inReverse)745 private boolean shouldPlayBackward(int iteration, boolean inReverse) { 746 if (iteration > 0 && mRepeatMode == REVERSE && 747 (iteration < (mRepeatCount + 1) || mRepeatCount == INFINITE)) { 748 // if we were seeked to some other iteration in a reversing animator, 749 // figure out the correct direction to start playing based on the iteration 750 if (inReverse) { 751 return (iteration % 2) == 0; 752 } else { 753 return (iteration % 2) != 0; 754 } 755 } else { 756 return inReverse; 757 } 758 } 759 760 /** 761 * Gets the current position of the animation in time, which is equal to the current 762 * time minus the time that the animation started. An animation that is not yet started will 763 * return a value of zero, unless the animation has has its play time set via 764 * {@link #setCurrentPlayTime(long)} or {@link #setCurrentFraction(float)}, in which case 765 * it will return the time that was set. 766 * 767 * @return The current position in time of the animation. 768 */ getCurrentPlayTime()769 public long getCurrentPlayTime() { 770 if (!mInitialized || (!mStarted && mSeekFraction < 0)) { 771 return 0; 772 } 773 if (mSeekFraction >= 0) { 774 return (long) (mDuration * mSeekFraction); 775 } 776 float durationScale = resolveDurationScale(); 777 if (durationScale == 0f) { 778 durationScale = 1f; 779 } 780 return (long) ((AnimationUtils.currentAnimationTimeMillis() - mStartTime) / durationScale); 781 } 782 783 /** 784 * The amount of time, in milliseconds, to delay starting the animation after 785 * {@link #start()} is called. 786 * 787 * @return the number of milliseconds to delay running the animation 788 */ 789 @Override getStartDelay()790 public long getStartDelay() { 791 return mStartDelay; 792 } 793 794 /** 795 * The amount of time, in milliseconds, to delay starting the animation after 796 * {@link #start()} is called. Note that the start delay should always be non-negative. Any 797 * negative start delay will be clamped to 0 on N and above. 798 * 799 * @param startDelay The amount of the delay, in milliseconds 800 */ 801 @Override setStartDelay(long startDelay)802 public void setStartDelay(long startDelay) { 803 // Clamp start delay to non-negative range. 804 if (startDelay < 0) { 805 Log.w(TAG, "Start delay should always be non-negative"); 806 startDelay = 0; 807 } 808 mStartDelay = startDelay; 809 } 810 811 /** 812 * The amount of time, in milliseconds, between each frame of the animation. This is a 813 * requested time that the animation will attempt to honor, but the actual delay between 814 * frames may be different, depending on system load and capabilities. This is a static 815 * function because the same delay will be applied to all animations, since they are all 816 * run off of a single timing loop. 817 * 818 * The frame delay may be ignored when the animation system uses an external timing 819 * source, such as the display refresh rate (vsync), to govern animations. 820 * 821 * Note that this method should be called from the same thread that {@link #start()} is 822 * called in order to check the frame delay for that animation. A runtime exception will be 823 * thrown if the calling thread does not have a Looper. 824 * 825 * @return the requested time between frames, in milliseconds 826 */ getFrameDelay()827 public static long getFrameDelay() { 828 return AnimationHandler.getInstance().getFrameDelay(); 829 } 830 831 /** 832 * The amount of time, in milliseconds, between each frame of the animation. This is a 833 * requested time that the animation will attempt to honor, but the actual delay between 834 * frames may be different, depending on system load and capabilities. This is a static 835 * function because the same delay will be applied to all animations, since they are all 836 * run off of a single timing loop. 837 * 838 * The frame delay may be ignored when the animation system uses an external timing 839 * source, such as the display refresh rate (vsync), to govern animations. 840 * 841 * Note that this method should be called from the same thread that {@link #start()} is 842 * called in order to have the new frame delay take effect on that animation. A runtime 843 * exception will be thrown if the calling thread does not have a Looper. 844 * 845 * @param frameDelay the requested time between frames, in milliseconds 846 */ setFrameDelay(long frameDelay)847 public static void setFrameDelay(long frameDelay) { 848 AnimationHandler.getInstance().setFrameDelay(frameDelay); 849 } 850 851 /** 852 * The most recent value calculated by this <code>ValueAnimator</code> when there is just one 853 * property being animated. This value is only sensible while the animation is running. The main 854 * purpose for this read-only property is to retrieve the value from the <code>ValueAnimator</code> 855 * during a call to {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)}, which 856 * is called during each animation frame, immediately after the value is calculated. 857 * 858 * @return animatedValue The value most recently calculated by this <code>ValueAnimator</code> for 859 * the single property being animated. If there are several properties being animated 860 * (specified by several PropertyValuesHolder objects in the constructor), this function 861 * returns the animated value for the first of those objects. 862 */ getAnimatedValue()863 public Object getAnimatedValue() { 864 if (mValues != null && mValues.length > 0) { 865 return mValues[0].getAnimatedValue(); 866 } 867 // Shouldn't get here; should always have values unless ValueAnimator was set up wrong 868 return null; 869 } 870 871 /** 872 * The most recent value calculated by this <code>ValueAnimator</code> for <code>propertyName</code>. 873 * The main purpose for this read-only property is to retrieve the value from the 874 * <code>ValueAnimator</code> during a call to 875 * {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)}, which 876 * is called during each animation frame, immediately after the value is calculated. 877 * 878 * @return animatedValue The value most recently calculated for the named property 879 * by this <code>ValueAnimator</code>. 880 */ getAnimatedValue(String propertyName)881 public Object getAnimatedValue(String propertyName) { 882 PropertyValuesHolder valuesHolder = mValuesMap.get(propertyName); 883 if (valuesHolder != null) { 884 return valuesHolder.getAnimatedValue(); 885 } else { 886 // At least avoid crashing if called with bogus propertyName 887 return null; 888 } 889 } 890 891 /** 892 * Sets how many times the animation should be repeated. If the repeat 893 * count is 0, the animation is never repeated. If the repeat count is 894 * greater than 0 or {@link #INFINITE}, the repeat mode will be taken 895 * into account. The repeat count is 0 by default. 896 * 897 * @param value the number of times the animation should be repeated 898 */ setRepeatCount(int value)899 public void setRepeatCount(int value) { 900 mRepeatCount = value; 901 } 902 /** 903 * Defines how many times the animation should repeat. The default value 904 * is 0. 905 * 906 * @return the number of times the animation should repeat, or {@link #INFINITE} 907 */ getRepeatCount()908 public int getRepeatCount() { 909 return mRepeatCount; 910 } 911 912 /** 913 * Defines what this animation should do when it reaches the end. This 914 * setting is applied only when the repeat count is either greater than 915 * 0 or {@link #INFINITE}. Defaults to {@link #RESTART}. 916 * 917 * @param value {@link #RESTART} or {@link #REVERSE} 918 */ setRepeatMode(@epeatMode int value)919 public void setRepeatMode(@RepeatMode int value) { 920 mRepeatMode = value; 921 } 922 923 /** 924 * Defines what this animation should do when it reaches the end. 925 * 926 * @return either one of {@link #REVERSE} or {@link #RESTART} 927 */ 928 @RepeatMode getRepeatMode()929 public int getRepeatMode() { 930 return mRepeatMode; 931 } 932 933 /** 934 * Adds a listener to the set of listeners that are sent update events through the life of 935 * an animation. This method is called on all listeners for every frame of the animation, 936 * after the values for the animation have been calculated. 937 * 938 * @param listener the listener to be added to the current set of listeners for this animation. 939 */ addUpdateListener(AnimatorUpdateListener listener)940 public void addUpdateListener(AnimatorUpdateListener listener) { 941 if (mUpdateListeners == null) { 942 mUpdateListeners = new ArrayList<AnimatorUpdateListener>(); 943 } 944 mUpdateListeners.add(listener); 945 } 946 947 /** 948 * Removes all listeners from the set listening to frame updates for this animation. 949 */ removeAllUpdateListeners()950 public void removeAllUpdateListeners() { 951 if (mUpdateListeners == null) { 952 return; 953 } 954 mUpdateListeners.clear(); 955 mUpdateListeners = null; 956 } 957 958 /** 959 * Removes a listener from the set listening to frame updates for this animation. 960 * 961 * @param listener the listener to be removed from the current set of update listeners 962 * for this animation. 963 */ removeUpdateListener(AnimatorUpdateListener listener)964 public void removeUpdateListener(AnimatorUpdateListener listener) { 965 if (mUpdateListeners == null) { 966 return; 967 } 968 mUpdateListeners.remove(listener); 969 if (mUpdateListeners.size() == 0) { 970 mUpdateListeners = null; 971 } 972 } 973 974 975 /** 976 * The time interpolator used in calculating the elapsed fraction of this animation. The 977 * interpolator determines whether the animation runs with linear or non-linear motion, 978 * such as acceleration and deceleration. The default value is 979 * {@link android.view.animation.AccelerateDecelerateInterpolator} 980 * 981 * @param value the interpolator to be used by this animation. A value of <code>null</code> 982 * will result in linear interpolation. 983 */ 984 @Override setInterpolator(TimeInterpolator value)985 public void setInterpolator(TimeInterpolator value) { 986 if (value != null) { 987 mInterpolator = value; 988 } else { 989 mInterpolator = new LinearInterpolator(); 990 } 991 } 992 993 /** 994 * Returns the timing interpolator that this ValueAnimator uses. 995 * 996 * @return The timing interpolator for this ValueAnimator. 997 */ 998 @Override getInterpolator()999 public TimeInterpolator getInterpolator() { 1000 return mInterpolator; 1001 } 1002 1003 /** 1004 * The type evaluator to be used when calculating the animated values of this animation. 1005 * The system will automatically assign a float or int evaluator based on the type 1006 * of <code>startValue</code> and <code>endValue</code> in the constructor. But if these values 1007 * are not one of these primitive types, or if different evaluation is desired (such as is 1008 * necessary with int values that represent colors), a custom evaluator needs to be assigned. 1009 * For example, when running an animation on color values, the {@link ArgbEvaluator} 1010 * should be used to get correct RGB color interpolation. 1011 * 1012 * <p>If this ValueAnimator has only one set of values being animated between, this evaluator 1013 * will be used for that set. If there are several sets of values being animated, which is 1014 * the case if PropertyValuesHolder objects were set on the ValueAnimator, then the evaluator 1015 * is assigned just to the first PropertyValuesHolder object.</p> 1016 * 1017 * @param value the evaluator to be used this animation 1018 */ setEvaluator(TypeEvaluator value)1019 public void setEvaluator(TypeEvaluator value) { 1020 if (value != null && mValues != null && mValues.length > 0) { 1021 mValues[0].setEvaluator(value); 1022 } 1023 } 1024 notifyStartListeners()1025 private void notifyStartListeners() { 1026 if (mListeners != null && !mStartListenersCalled) { 1027 ArrayList<AnimatorListener> tmpListeners = 1028 (ArrayList<AnimatorListener>) mListeners.clone(); 1029 int numListeners = tmpListeners.size(); 1030 for (int i = 0; i < numListeners; ++i) { 1031 tmpListeners.get(i).onAnimationStart(this, mReversing); 1032 } 1033 } 1034 mStartListenersCalled = true; 1035 } 1036 1037 /** 1038 * Start the animation playing. This version of start() takes a boolean flag that indicates 1039 * whether the animation should play in reverse. The flag is usually false, but may be set 1040 * to true if called from the reverse() method. 1041 * 1042 * <p>The animation started by calling this method will be run on the thread that called 1043 * this method. This thread should have a Looper on it (a runtime exception will be thrown if 1044 * this is not the case). Also, if the animation will animate 1045 * properties of objects in the view hierarchy, then the calling thread should be the UI 1046 * thread for that view hierarchy.</p> 1047 * 1048 * @param playBackwards Whether the ValueAnimator should start playing in reverse. 1049 */ start(boolean playBackwards)1050 private void start(boolean playBackwards) { 1051 if (Looper.myLooper() == null) { 1052 throw new AndroidRuntimeException("Animators may only be run on Looper threads"); 1053 } 1054 mReversing = playBackwards; 1055 mSelfPulse = !mSuppressSelfPulseRequested; 1056 // Special case: reversing from seek-to-0 should act as if not seeked at all. 1057 if (playBackwards && mSeekFraction != -1 && mSeekFraction != 0) { 1058 if (mRepeatCount == INFINITE) { 1059 // Calculate the fraction of the current iteration. 1060 float fraction = (float) (mSeekFraction - Math.floor(mSeekFraction)); 1061 mSeekFraction = 1 - fraction; 1062 } else { 1063 mSeekFraction = 1 + mRepeatCount - mSeekFraction; 1064 } 1065 } 1066 mStarted = true; 1067 mPaused = false; 1068 mRunning = false; 1069 mAnimationEndRequested = false; 1070 // Resets mLastFrameTime when start() is called, so that if the animation was running, 1071 // calling start() would put the animation in the 1072 // started-but-not-yet-reached-the-first-frame phase. 1073 mLastFrameTime = -1; 1074 mFirstFrameTime = -1; 1075 mStartTime = -1; 1076 addAnimationCallback(0); 1077 1078 if (mStartDelay == 0 || mSeekFraction >= 0 || mReversing) { 1079 // If there's no start delay, init the animation and notify start listeners right away 1080 // to be consistent with the previous behavior. Otherwise, postpone this until the first 1081 // frame after the start delay. 1082 startAnimation(); 1083 if (mSeekFraction == -1) { 1084 // No seek, start at play time 0. Note that the reason we are not using fraction 0 1085 // is because for animations with 0 duration, we want to be consistent with pre-N 1086 // behavior: skip to the final value immediately. 1087 setCurrentPlayTime(0); 1088 } else { 1089 setCurrentFraction(mSeekFraction); 1090 } 1091 } 1092 } 1093 startWithoutPulsing(boolean inReverse)1094 void startWithoutPulsing(boolean inReverse) { 1095 mSuppressSelfPulseRequested = true; 1096 if (inReverse) { 1097 reverse(); 1098 } else { 1099 start(); 1100 } 1101 mSuppressSelfPulseRequested = false; 1102 } 1103 1104 @Override start()1105 public void start() { 1106 start(false); 1107 } 1108 1109 @Override cancel()1110 public void cancel() { 1111 if (Looper.myLooper() == null) { 1112 throw new AndroidRuntimeException("Animators may only be run on Looper threads"); 1113 } 1114 1115 // If end has already been requested, through a previous end() or cancel() call, no-op 1116 // until animation starts again. 1117 if (mAnimationEndRequested) { 1118 return; 1119 } 1120 1121 // Only cancel if the animation is actually running or has been started and is about 1122 // to run 1123 // Only notify listeners if the animator has actually started 1124 if ((mStarted || mRunning) && mListeners != null) { 1125 if (!mRunning) { 1126 // If it's not yet running, then start listeners weren't called. Call them now. 1127 notifyStartListeners(); 1128 } 1129 ArrayList<AnimatorListener> tmpListeners = 1130 (ArrayList<AnimatorListener>) mListeners.clone(); 1131 for (AnimatorListener listener : tmpListeners) { 1132 listener.onAnimationCancel(this); 1133 } 1134 } 1135 endAnimation(); 1136 1137 } 1138 1139 @Override end()1140 public void end() { 1141 if (Looper.myLooper() == null) { 1142 throw new AndroidRuntimeException("Animators may only be run on Looper threads"); 1143 } 1144 if (!mRunning) { 1145 // Special case if the animation has not yet started; get it ready for ending 1146 startAnimation(); 1147 mStarted = true; 1148 } else if (!mInitialized) { 1149 initAnimation(); 1150 } 1151 animateValue(shouldPlayBackward(mRepeatCount, mReversing) ? 0f : 1f); 1152 endAnimation(); 1153 } 1154 1155 @Override resume()1156 public void resume() { 1157 if (Looper.myLooper() == null) { 1158 throw new AndroidRuntimeException("Animators may only be resumed from the same " + 1159 "thread that the animator was started on"); 1160 } 1161 if (mPaused && !mResumed) { 1162 mResumed = true; 1163 if (mPauseTime > 0) { 1164 addAnimationCallback(0); 1165 } 1166 } 1167 super.resume(); 1168 } 1169 1170 @Override pause()1171 public void pause() { 1172 boolean previouslyPaused = mPaused; 1173 super.pause(); 1174 if (!previouslyPaused && mPaused) { 1175 mPauseTime = -1; 1176 mResumed = false; 1177 } 1178 } 1179 1180 @Override isRunning()1181 public boolean isRunning() { 1182 return mRunning; 1183 } 1184 1185 @Override isStarted()1186 public boolean isStarted() { 1187 return mStarted; 1188 } 1189 1190 /** 1191 * Plays the ValueAnimator in reverse. If the animation is already running, 1192 * it will stop itself and play backwards from the point reached when reverse was called. 1193 * If the animation is not currently running, then it will start from the end and 1194 * play backwards. This behavior is only set for the current animation; future playing 1195 * of the animation will use the default behavior of playing forward. 1196 */ 1197 @Override reverse()1198 public void reverse() { 1199 if (isPulsingInternal()) { 1200 long currentTime = AnimationUtils.currentAnimationTimeMillis(); 1201 long currentPlayTime = currentTime - mStartTime; 1202 long timeLeft = getScaledDuration() - currentPlayTime; 1203 mStartTime = currentTime - timeLeft; 1204 mStartTimeCommitted = true; // do not allow start time to be compensated for jank 1205 mReversing = !mReversing; 1206 } else if (mStarted) { 1207 mReversing = !mReversing; 1208 end(); 1209 } else { 1210 start(true); 1211 } 1212 } 1213 1214 /** 1215 * @hide 1216 */ 1217 @Override canReverse()1218 public boolean canReverse() { 1219 return true; 1220 } 1221 1222 /** 1223 * Called internally to end an animation by removing it from the animations list. Must be 1224 * called on the UI thread. 1225 */ endAnimation()1226 private void endAnimation() { 1227 if (mAnimationEndRequested) { 1228 return; 1229 } 1230 removeAnimationCallback(); 1231 1232 mAnimationEndRequested = true; 1233 mPaused = false; 1234 boolean notify = (mStarted || mRunning) && mListeners != null; 1235 if (notify && !mRunning) { 1236 // If it's not yet running, then start listeners weren't called. Call them now. 1237 notifyStartListeners(); 1238 } 1239 mRunning = false; 1240 mStarted = false; 1241 mStartListenersCalled = false; 1242 mLastFrameTime = -1; 1243 mFirstFrameTime = -1; 1244 mStartTime = -1; 1245 if (notify && mListeners != null) { 1246 ArrayList<AnimatorListener> tmpListeners = 1247 (ArrayList<AnimatorListener>) mListeners.clone(); 1248 int numListeners = tmpListeners.size(); 1249 for (int i = 0; i < numListeners; ++i) { 1250 tmpListeners.get(i).onAnimationEnd(this, mReversing); 1251 } 1252 } 1253 // mReversing needs to be reset *after* notifying the listeners for the end callbacks. 1254 mReversing = false; 1255 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 1256 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, getNameForTrace(), 1257 System.identityHashCode(this)); 1258 } 1259 } 1260 1261 /** 1262 * Called internally to start an animation by adding it to the active animations list. Must be 1263 * called on the UI thread. 1264 */ startAnimation()1265 private void startAnimation() { 1266 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 1267 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, getNameForTrace(), 1268 System.identityHashCode(this)); 1269 } 1270 1271 mAnimationEndRequested = false; 1272 initAnimation(); 1273 mRunning = true; 1274 if (mSeekFraction >= 0) { 1275 mOverallFraction = mSeekFraction; 1276 } else { 1277 mOverallFraction = 0f; 1278 } 1279 if (mListeners != null) { 1280 notifyStartListeners(); 1281 } 1282 } 1283 1284 /** 1285 * Internal only: This tracks whether the animation has gotten on the animation loop. Note 1286 * this is different than {@link #isRunning()} in that the latter tracks the time after start() 1287 * is called (or after start delay if any), which may be before the animation loop starts. 1288 */ isPulsingInternal()1289 private boolean isPulsingInternal() { 1290 return mLastFrameTime >= 0; 1291 } 1292 1293 /** 1294 * Returns the name of this animator for debugging purposes. 1295 */ getNameForTrace()1296 String getNameForTrace() { 1297 return "animator"; 1298 } 1299 1300 /** 1301 * Applies an adjustment to the animation to compensate for jank between when 1302 * the animation first ran and when the frame was drawn. 1303 * @hide 1304 */ commitAnimationFrame(long frameTime)1305 public void commitAnimationFrame(long frameTime) { 1306 if (!mStartTimeCommitted) { 1307 mStartTimeCommitted = true; 1308 long adjustment = frameTime - mLastFrameTime; 1309 if (adjustment > 0) { 1310 mStartTime += adjustment; 1311 if (DEBUG) { 1312 Log.d(TAG, "Adjusted start time by " + adjustment + " ms: " + toString()); 1313 } 1314 } 1315 } 1316 } 1317 1318 /** 1319 * This internal function processes a single animation frame for a given animation. The 1320 * currentTime parameter is the timing pulse sent by the handler, used to calculate the 1321 * elapsed duration, and therefore 1322 * the elapsed fraction, of the animation. The return value indicates whether the animation 1323 * should be ended (which happens when the elapsed time of the animation exceeds the 1324 * animation's duration, including the repeatCount). 1325 * 1326 * @param currentTime The current time, as tracked by the static timing handler 1327 * @return true if the animation's duration, including any repetitions due to 1328 * <code>repeatCount</code> has been exceeded and the animation should be ended. 1329 */ animateBasedOnTime(long currentTime)1330 boolean animateBasedOnTime(long currentTime) { 1331 boolean done = false; 1332 if (mRunning) { 1333 final long scaledDuration = getScaledDuration(); 1334 final float fraction = scaledDuration > 0 ? 1335 (float)(currentTime - mStartTime) / scaledDuration : 1f; 1336 final float lastFraction = mOverallFraction; 1337 final boolean newIteration = (int) fraction > (int) lastFraction; 1338 final boolean lastIterationFinished = (fraction >= mRepeatCount + 1) && 1339 (mRepeatCount != INFINITE); 1340 if (scaledDuration == 0) { 1341 // 0 duration animator, ignore the repeat count and skip to the end 1342 done = true; 1343 } else if (newIteration && !lastIterationFinished) { 1344 // Time to repeat 1345 if (mListeners != null) { 1346 int numListeners = mListeners.size(); 1347 for (int i = 0; i < numListeners; ++i) { 1348 mListeners.get(i).onAnimationRepeat(this); 1349 } 1350 } 1351 } else if (lastIterationFinished) { 1352 done = true; 1353 } 1354 mOverallFraction = clampFraction(fraction); 1355 float currentIterationFraction = getCurrentIterationFraction( 1356 mOverallFraction, mReversing); 1357 animateValue(currentIterationFraction); 1358 } 1359 return done; 1360 } 1361 1362 /** 1363 * Internal use only. 1364 * 1365 * This method does not modify any fields of the animation. It should be called when seeking 1366 * in an AnimatorSet. When the last play time and current play time are of different repeat 1367 * iterations, 1368 * {@link android.view.animation.Animation.AnimationListener#onAnimationRepeat(Animation)} 1369 * will be called. 1370 */ 1371 @Override animateBasedOnPlayTime(long currentPlayTime, long lastPlayTime, boolean inReverse)1372 void animateBasedOnPlayTime(long currentPlayTime, long lastPlayTime, boolean inReverse) { 1373 if (currentPlayTime < 0 || lastPlayTime < 0) { 1374 throw new UnsupportedOperationException("Error: Play time should never be negative."); 1375 } 1376 1377 initAnimation(); 1378 // Check whether repeat callback is needed only when repeat count is non-zero 1379 if (mRepeatCount > 0) { 1380 int iteration = (int) (currentPlayTime / mDuration); 1381 int lastIteration = (int) (lastPlayTime / mDuration); 1382 1383 // Clamp iteration to [0, mRepeatCount] 1384 iteration = Math.min(iteration, mRepeatCount); 1385 lastIteration = Math.min(lastIteration, mRepeatCount); 1386 1387 if (iteration != lastIteration) { 1388 if (mListeners != null) { 1389 int numListeners = mListeners.size(); 1390 for (int i = 0; i < numListeners; ++i) { 1391 mListeners.get(i).onAnimationRepeat(this); 1392 } 1393 } 1394 } 1395 } 1396 1397 if (mRepeatCount != INFINITE && currentPlayTime >= (mRepeatCount + 1) * mDuration) { 1398 skipToEndValue(inReverse); 1399 } else { 1400 // Find the current fraction: 1401 float fraction = currentPlayTime / (float) mDuration; 1402 fraction = getCurrentIterationFraction(fraction, inReverse); 1403 animateValue(fraction); 1404 } 1405 } 1406 1407 /** 1408 * Internal use only. 1409 * Skips the animation value to end/start, depending on whether the play direction is forward 1410 * or backward. 1411 * 1412 * @param inReverse whether the end value is based on a reverse direction. If yes, this is 1413 * equivalent to skip to start value in a forward playing direction. 1414 */ skipToEndValue(boolean inReverse)1415 void skipToEndValue(boolean inReverse) { 1416 initAnimation(); 1417 float endFraction = inReverse ? 0f : 1f; 1418 if (mRepeatCount % 2 == 1 && mRepeatMode == REVERSE) { 1419 // This would end on fraction = 0 1420 endFraction = 0f; 1421 } 1422 animateValue(endFraction); 1423 } 1424 1425 @Override isInitialized()1426 boolean isInitialized() { 1427 return mInitialized; 1428 } 1429 1430 /** 1431 * Processes a frame of the animation, adjusting the start time if needed. 1432 * 1433 * @param frameTime The frame time. 1434 * @return true if the animation has ended. 1435 * @hide 1436 */ doAnimationFrame(long frameTime)1437 public final boolean doAnimationFrame(long frameTime) { 1438 if (mStartTime < 0) { 1439 // First frame. If there is start delay, start delay count down will happen *after* this 1440 // frame. 1441 mStartTime = mReversing 1442 ? frameTime 1443 : frameTime + (long) (mStartDelay * resolveDurationScale()); 1444 } 1445 1446 // Handle pause/resume 1447 if (mPaused) { 1448 mPauseTime = frameTime; 1449 removeAnimationCallback(); 1450 return false; 1451 } else if (mResumed) { 1452 mResumed = false; 1453 if (mPauseTime > 0) { 1454 // Offset by the duration that the animation was paused 1455 mStartTime += (frameTime - mPauseTime); 1456 } 1457 } 1458 1459 if (!mRunning) { 1460 // If not running, that means the animation is in the start delay phase of a forward 1461 // running animation. In the case of reversing, we want to run start delay in the end. 1462 if (mStartTime > frameTime && mSeekFraction == -1) { 1463 // This is when no seek fraction is set during start delay. If developers change the 1464 // seek fraction during the delay, animation will start from the seeked position 1465 // right away. 1466 return false; 1467 } else { 1468 // If mRunning is not set by now, that means non-zero start delay, 1469 // no seeking, not reversing. At this point, start delay has passed. 1470 mRunning = true; 1471 startAnimation(); 1472 } 1473 } 1474 1475 if (mLastFrameTime < 0) { 1476 if (mSeekFraction >= 0) { 1477 long seekTime = (long) (getScaledDuration() * mSeekFraction); 1478 mStartTime = frameTime - seekTime; 1479 mSeekFraction = -1; 1480 } 1481 mStartTimeCommitted = false; // allow start time to be compensated for jank 1482 } 1483 mLastFrameTime = frameTime; 1484 // The frame time might be before the start time during the first frame of 1485 // an animation. The "current time" must always be on or after the start 1486 // time to avoid animating frames at negative time intervals. In practice, this 1487 // is very rare and only happens when seeking backwards. 1488 final long currentTime = Math.max(frameTime, mStartTime); 1489 boolean finished = animateBasedOnTime(currentTime); 1490 1491 if (finished) { 1492 endAnimation(); 1493 } 1494 return finished; 1495 } 1496 1497 @Override pulseAnimationFrame(long frameTime)1498 boolean pulseAnimationFrame(long frameTime) { 1499 if (mSelfPulse) { 1500 // Pulse animation frame will *always* be after calling start(). If mSelfPulse isn't 1501 // set to false at this point, that means child animators did not call super's start(). 1502 // This can happen when the Animator is just a non-animating wrapper around a real 1503 // functional animation. In this case, we can't really pulse a frame into the animation, 1504 // because the animation cannot necessarily be properly initialized (i.e. no start/end 1505 // values set). 1506 return false; 1507 } 1508 return doAnimationFrame(frameTime); 1509 } 1510 addOneShotCommitCallback()1511 private void addOneShotCommitCallback() { 1512 if (!mSelfPulse) { 1513 return; 1514 } 1515 getAnimationHandler().addOneShotCommitCallback(this); 1516 } 1517 removeAnimationCallback()1518 private void removeAnimationCallback() { 1519 if (!mSelfPulse) { 1520 return; 1521 } 1522 getAnimationHandler().removeCallback(this); 1523 } 1524 addAnimationCallback(long delay)1525 private void addAnimationCallback(long delay) { 1526 if (!mSelfPulse) { 1527 return; 1528 } 1529 getAnimationHandler().addAnimationFrameCallback(this, delay); 1530 } 1531 1532 /** 1533 * Returns the current animation fraction, which is the elapsed/interpolated fraction used in 1534 * the most recent frame update on the animation. 1535 * 1536 * @return Elapsed/interpolated fraction of the animation. 1537 */ getAnimatedFraction()1538 public float getAnimatedFraction() { 1539 return mCurrentFraction; 1540 } 1541 1542 /** 1543 * This method is called with the elapsed fraction of the animation during every 1544 * animation frame. This function turns the elapsed fraction into an interpolated fraction 1545 * and then into an animated value (from the evaluator. The function is called mostly during 1546 * animation updates, but it is also called when the <code>end()</code> 1547 * function is called, to set the final value on the property. 1548 * 1549 * <p>Overrides of this method must call the superclass to perform the calculation 1550 * of the animated value.</p> 1551 * 1552 * @param fraction The elapsed fraction of the animation. 1553 */ 1554 @CallSuper 1555 @UnsupportedAppUsage animateValue(float fraction)1556 void animateValue(float fraction) { 1557 fraction = mInterpolator.getInterpolation(fraction); 1558 mCurrentFraction = fraction; 1559 int numValues = mValues.length; 1560 for (int i = 0; i < numValues; ++i) { 1561 mValues[i].calculateValue(fraction); 1562 } 1563 if (mUpdateListeners != null) { 1564 int numListeners = mUpdateListeners.size(); 1565 for (int i = 0; i < numListeners; ++i) { 1566 mUpdateListeners.get(i).onAnimationUpdate(this); 1567 } 1568 } 1569 } 1570 1571 @Override clone()1572 public ValueAnimator clone() { 1573 final ValueAnimator anim = (ValueAnimator) super.clone(); 1574 if (mUpdateListeners != null) { 1575 anim.mUpdateListeners = new ArrayList<AnimatorUpdateListener>(mUpdateListeners); 1576 } 1577 anim.mSeekFraction = -1; 1578 anim.mReversing = false; 1579 anim.mInitialized = false; 1580 anim.mStarted = false; 1581 anim.mRunning = false; 1582 anim.mPaused = false; 1583 anim.mResumed = false; 1584 anim.mStartListenersCalled = false; 1585 anim.mStartTime = -1; 1586 anim.mStartTimeCommitted = false; 1587 anim.mAnimationEndRequested = false; 1588 anim.mPauseTime = -1; 1589 anim.mLastFrameTime = -1; 1590 anim.mFirstFrameTime = -1; 1591 anim.mOverallFraction = 0; 1592 anim.mCurrentFraction = 0; 1593 anim.mSelfPulse = true; 1594 anim.mSuppressSelfPulseRequested = false; 1595 1596 PropertyValuesHolder[] oldValues = mValues; 1597 if (oldValues != null) { 1598 int numValues = oldValues.length; 1599 anim.mValues = new PropertyValuesHolder[numValues]; 1600 anim.mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues); 1601 for (int i = 0; i < numValues; ++i) { 1602 PropertyValuesHolder newValuesHolder = oldValues[i].clone(); 1603 anim.mValues[i] = newValuesHolder; 1604 anim.mValuesMap.put(newValuesHolder.getPropertyName(), newValuesHolder); 1605 } 1606 } 1607 return anim; 1608 } 1609 1610 /** 1611 * Implementors of this interface can add themselves as update listeners 1612 * to an <code>ValueAnimator</code> instance to receive callbacks on every animation 1613 * frame, after the current frame's values have been calculated for that 1614 * <code>ValueAnimator</code>. 1615 */ 1616 public static interface AnimatorUpdateListener { 1617 /** 1618 * <p>Notifies the occurrence of another frame of the animation.</p> 1619 * 1620 * @param animation The animation which was repeated. 1621 */ onAnimationUpdate(ValueAnimator animation)1622 void onAnimationUpdate(ValueAnimator animation); 1623 1624 } 1625 1626 /** 1627 * Return the number of animations currently running. 1628 * 1629 * Used by StrictMode internally to annotate violations. 1630 * May be called on arbitrary threads! 1631 * 1632 * @hide 1633 */ getCurrentAnimationsCount()1634 public static int getCurrentAnimationsCount() { 1635 return AnimationHandler.getAnimationCount(); 1636 } 1637 1638 @Override toString()1639 public String toString() { 1640 String returnVal = "ValueAnimator@" + Integer.toHexString(hashCode()); 1641 if (mValues != null) { 1642 for (int i = 0; i < mValues.length; ++i) { 1643 returnVal += "\n " + mValues[i].toString(); 1644 } 1645 } 1646 return returnVal; 1647 } 1648 1649 /** 1650 * <p>Whether or not the ValueAnimator is allowed to run asynchronously off of 1651 * the UI thread. This is a hint that informs the ValueAnimator that it is 1652 * OK to run the animation off-thread, however ValueAnimator may decide 1653 * that it must run the animation on the UI thread anyway. For example if there 1654 * is an {@link AnimatorUpdateListener} the animation will run on the UI thread, 1655 * regardless of the value of this hint.</p> 1656 * 1657 * <p>Regardless of whether or not the animation runs asynchronously, all 1658 * listener callbacks will be called on the UI thread.</p> 1659 * 1660 * <p>To be able to use this hint the following must be true:</p> 1661 * <ol> 1662 * <li>{@link #getAnimatedFraction()} is not needed (it will return undefined values).</li> 1663 * <li>The animator is immutable while {@link #isStarted()} is true. Requests 1664 * to change values, duration, delay, etc... may be ignored.</li> 1665 * <li>Lifecycle callback events may be asynchronous. Events such as 1666 * {@link Animator.AnimatorListener#onAnimationEnd(Animator)} or 1667 * {@link Animator.AnimatorListener#onAnimationRepeat(Animator)} may end up delayed 1668 * as they must be posted back to the UI thread, and any actions performed 1669 * by those callbacks (such as starting new animations) will not happen 1670 * in the same frame.</li> 1671 * <li>State change requests ({@link #cancel()}, {@link #end()}, {@link #reverse()}, etc...) 1672 * may be asynchronous. It is guaranteed that all state changes that are 1673 * performed on the UI thread in the same frame will be applied as a single 1674 * atomic update, however that frame may be the current frame, 1675 * the next frame, or some future frame. This will also impact the observed 1676 * state of the Animator. For example, {@link #isStarted()} may still return true 1677 * after a call to {@link #end()}. Using the lifecycle callbacks is preferred over 1678 * queries to {@link #isStarted()}, {@link #isRunning()}, and {@link #isPaused()} 1679 * for this reason.</li> 1680 * </ol> 1681 * @hide 1682 */ 1683 @Override setAllowRunningAsynchronously(boolean mayRunAsync)1684 public void setAllowRunningAsynchronously(boolean mayRunAsync) { 1685 // It is up to subclasses to support this, if they can. 1686 } 1687 1688 /** 1689 * @return The {@link AnimationHandler} that will be used to schedule updates for this animator. 1690 * @hide 1691 */ getAnimationHandler()1692 public AnimationHandler getAnimationHandler() { 1693 return mAnimationHandler != null ? mAnimationHandler : AnimationHandler.getInstance(); 1694 } 1695 1696 /** 1697 * Sets the animation handler used to schedule updates for this animator or {@code null} to use 1698 * the default handler. 1699 * @hide 1700 */ setAnimationHandler(@ullable AnimationHandler animationHandler)1701 public void setAnimationHandler(@Nullable AnimationHandler animationHandler) { 1702 mAnimationHandler = animationHandler; 1703 } 1704 } 1705