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