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.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.TestApi; 22 import android.compat.annotation.UnsupportedAppUsage; 23 import android.content.pm.ActivityInfo.Config; 24 import android.content.res.ConstantState; 25 import android.os.Build; 26 import android.util.LongArray; 27 28 import java.util.ArrayList; 29 import java.util.concurrent.atomic.AtomicReference; 30 31 /** 32 * This is the superclass for classes which provide basic support for animations which can be 33 * started, ended, and have <code>AnimatorListeners</code> added to them. 34 */ 35 public abstract class Animator implements Cloneable { 36 37 /** 38 * The value used to indicate infinite duration (e.g. when Animators repeat infinitely). 39 */ 40 public static final long DURATION_INFINITE = -1; 41 /** 42 * The set of listeners to be sent events through the life of an animation. 43 */ 44 ArrayList<AnimatorListener> mListeners = null; 45 46 /** 47 * The set of listeners to be sent pause/resume events through the life 48 * of an animation. 49 */ 50 ArrayList<AnimatorPauseListener> mPauseListeners = null; 51 52 /** 53 * Whether this animator is currently in a paused state. 54 */ 55 boolean mPaused = false; 56 57 /** 58 * A set of flags which identify the type of configuration changes that can affect this 59 * Animator. Used by the Animator cache. 60 */ 61 @Config int mChangingConfigurations = 0; 62 63 /** 64 * If this animator is inflated from a constant state, keep a reference to it so that 65 * ConstantState will not be garbage collected until this animator is collected 66 */ 67 private AnimatorConstantState mConstantState; 68 69 /** 70 * backing field for backgroundPauseDelay property. This could be simply a hardcoded 71 * value in AnimationHandler, but it is useful to be able to change the value in tests. 72 */ 73 private static long sBackgroundPauseDelay = 1000; 74 75 /** 76 * A cache of the values in a list. Used so that when calling the list, we have a copy 77 * of it in case the list is modified while iterating. The array can be reused to avoid 78 * allocation on every notification. 79 */ 80 private AtomicReference<Object[]> mCachedList = new AtomicReference<>(); 81 82 /** 83 * Tracks whether we've notified listeners of the onAnimationStart() event. This can be 84 * complex to keep track of since we notify listeners at different times depending on 85 * startDelay and whether start() was called before end(). 86 */ 87 boolean mStartListenersCalled = false; 88 89 /** 90 * Sets the duration for delaying pausing animators when apps go into the background. 91 * Used by AnimationHandler when requested to pause animators. 92 * 93 * @hide 94 */ 95 @TestApi setBackgroundPauseDelay(long value)96 public static void setBackgroundPauseDelay(long value) { 97 sBackgroundPauseDelay = value; 98 } 99 100 /** 101 * Gets the duration for delaying pausing animators when apps go into the background. 102 * Used by AnimationHandler when requested to pause animators. 103 * 104 * @hide 105 */ 106 @TestApi getBackgroundPauseDelay()107 public static long getBackgroundPauseDelay() { 108 return sBackgroundPauseDelay; 109 } 110 111 /** 112 * Sets the behavior of animator pausing when apps go into the background. 113 * This is exposed as a test API for verification, but is intended for use by internal/ 114 * platform code, potentially for use by a system property that could disable it 115 * system wide. 116 * 117 * @param enable Enable (default behavior) or disable background pausing behavior. 118 * @hide 119 */ 120 @TestApi setAnimatorPausingEnabled(boolean enable)121 public static void setAnimatorPausingEnabled(boolean enable) { 122 AnimationHandler.setAnimatorPausingEnabled(enable); 123 AnimationHandler.setOverrideAnimatorPausingSystemProperty(!enable); 124 } 125 126 /** 127 * Starts this animation. If the animation has a nonzero startDelay, the animation will start 128 * running after that delay elapses. A non-delayed animation will have its initial 129 * value(s) set immediately, followed by calls to 130 * {@link AnimatorListener#onAnimationStart(Animator)} for any listeners of this animator. 131 * 132 * <p>The animation started by calling this method will be run on the thread that called 133 * this method. This thread should have a Looper on it (a runtime exception will be thrown if 134 * this is not the case). Also, if the animation will animate 135 * properties of objects in the view hierarchy, then the calling thread should be the UI 136 * thread for that view hierarchy.</p> 137 * 138 */ start()139 public void start() { 140 } 141 142 /** 143 * Cancels the animation. Unlike {@link #end()}, <code>cancel()</code> causes the animation to 144 * stop in its tracks, sending an 145 * {@link android.animation.Animator.AnimatorListener#onAnimationCancel(Animator)} to 146 * its listeners, followed by an 147 * {@link android.animation.Animator.AnimatorListener#onAnimationEnd(Animator)} message. 148 * 149 * <p>This method must be called on the thread that is running the animation.</p> 150 */ cancel()151 public void cancel() { 152 } 153 154 /** 155 * Ends the animation. This causes the animation to assign the end value of the property being 156 * animated, then calling the 157 * {@link android.animation.Animator.AnimatorListener#onAnimationEnd(Animator)} method on 158 * its listeners. 159 * 160 * <p>This method must be called on the thread that is running the animation.</p> 161 */ end()162 public void end() { 163 } 164 165 /** 166 * Pauses a running animation. This method should only be called on the same thread on 167 * which the animation was started. If the animation has not yet been {@link 168 * #isStarted() started} or has since ended, then the call is ignored. Paused 169 * animations can be resumed by calling {@link #resume()}. 170 * 171 * @see #resume() 172 * @see #isPaused() 173 * @see AnimatorPauseListener 174 */ pause()175 public void pause() { 176 // We only want to pause started Animators or animators that setCurrentPlayTime() 177 // have been called on. mStartListenerCalled will be true if seek has happened. 178 if ((isStarted() || mStartListenersCalled) && !mPaused) { 179 mPaused = true; 180 notifyPauseListeners(AnimatorCaller.ON_PAUSE); 181 } 182 } 183 184 /** 185 * Resumes a paused animation, causing the animator to pick up where it left off 186 * when it was paused. This method should only be called on the same thread on 187 * which the animation was started. Calls to resume() on an animator that is 188 * not currently paused will be ignored. 189 * 190 * @see #pause() 191 * @see #isPaused() 192 * @see AnimatorPauseListener 193 */ resume()194 public void resume() { 195 if (mPaused) { 196 mPaused = false; 197 notifyPauseListeners(AnimatorCaller.ON_RESUME); 198 } 199 } 200 201 /** 202 * Returns whether this animator is currently in a paused state. 203 * 204 * @return True if the animator is currently paused, false otherwise. 205 * 206 * @see #pause() 207 * @see #resume() 208 */ isPaused()209 public boolean isPaused() { 210 return mPaused; 211 } 212 213 /** 214 * The amount of time, in milliseconds, to delay processing the animation 215 * after {@link #start()} is called. 216 * 217 * @return the number of milliseconds to delay running the animation 218 */ getStartDelay()219 public abstract long getStartDelay(); 220 221 /** 222 * The amount of time, in milliseconds, to delay processing the animation 223 * after {@link #start()} is called. 224 225 * @param startDelay The amount of the delay, in milliseconds 226 */ setStartDelay(long startDelay)227 public abstract void setStartDelay(long startDelay); 228 229 /** 230 * Sets the duration of the animation. 231 * 232 * @param duration The length of the animation, in milliseconds. 233 */ setDuration(long duration)234 public abstract Animator setDuration(long duration); 235 236 /** 237 * Gets the duration of the animation. 238 * 239 * @return The length of the animation, in milliseconds. 240 */ getDuration()241 public abstract long getDuration(); 242 243 /** 244 * Gets the total duration of the animation, accounting for animation sequences, start delay, 245 * and repeating. Return {@link #DURATION_INFINITE} if the duration is infinite. 246 * 247 * @return Total time an animation takes to finish, starting from the time {@link #start()} 248 * is called. {@link #DURATION_INFINITE} will be returned if the animation or any 249 * child animation repeats infinite times. 250 */ getTotalDuration()251 public long getTotalDuration() { 252 long duration = getDuration(); 253 if (duration == DURATION_INFINITE) { 254 return DURATION_INFINITE; 255 } else { 256 return getStartDelay() + duration; 257 } 258 } 259 260 /** 261 * The time interpolator used in calculating the elapsed fraction of the 262 * animation. The interpolator determines whether the animation runs with 263 * linear or non-linear motion, such as acceleration and deceleration. The 264 * default value is {@link android.view.animation.AccelerateDecelerateInterpolator}. 265 * 266 * @param value the interpolator to be used by this animation 267 */ setInterpolator(TimeInterpolator value)268 public abstract void setInterpolator(TimeInterpolator value); 269 270 /** 271 * Returns the timing interpolator that this animation uses. 272 * 273 * @return The timing interpolator for this animation. 274 */ getInterpolator()275 public TimeInterpolator getInterpolator() { 276 return null; 277 } 278 279 /** 280 * Returns whether this Animator is currently running (having been started and gone past any 281 * initial startDelay period and not yet ended). 282 * 283 * @return Whether the Animator is running. 284 */ isRunning()285 public abstract boolean isRunning(); 286 287 /** 288 * Returns whether this Animator has been started and not yet ended. For reusable 289 * Animators (which most Animators are, apart from the one-shot animator produced by 290 * {@link android.view.ViewAnimationUtils#createCircularReveal( 291 * android.view.View, int, int, float, float) createCircularReveal()}), 292 * this state is a superset of {@link #isRunning()}, because an Animator with a 293 * nonzero {@link #getStartDelay() startDelay} will return true for {@link #isStarted()} during 294 * the delay phase, whereas {@link #isRunning()} will return true only after the delay phase 295 * is complete. Non-reusable animators will always return true after they have been 296 * started, because they cannot return to a non-started state. 297 * 298 * @return Whether the Animator has been started and not yet ended. 299 */ isStarted()300 public boolean isStarted() { 301 // Default method returns value for isRunning(). Subclasses should override to return a 302 // real value. 303 return isRunning(); 304 } 305 306 /** 307 * Adds a listener to the set of listeners that are sent events through the life of an 308 * animation, such as start, repeat, and end. 309 * 310 * @param listener the listener to be added to the current set of listeners for this animation. 311 */ addListener(AnimatorListener listener)312 public void addListener(AnimatorListener listener) { 313 if (mListeners == null) { 314 mListeners = new ArrayList<AnimatorListener>(); 315 } 316 mListeners.add(listener); 317 } 318 319 /** 320 * Removes a listener from the set listening to this animation. 321 * 322 * @param listener the listener to be removed from the current set of listeners for this 323 * animation. 324 */ removeListener(AnimatorListener listener)325 public void removeListener(AnimatorListener listener) { 326 if (mListeners == null) { 327 return; 328 } 329 mListeners.remove(listener); 330 if (mListeners.size() == 0) { 331 mListeners = null; 332 } 333 } 334 335 /** 336 * Gets the set of {@link android.animation.Animator.AnimatorListener} objects that are currently 337 * listening for events on this <code>Animator</code> object. 338 * 339 * @return ArrayList<AnimatorListener> The set of listeners. 340 */ getListeners()341 public ArrayList<AnimatorListener> getListeners() { 342 return mListeners; 343 } 344 345 /** 346 * Adds a pause listener to this animator. 347 * 348 * @param listener the listener to be added to the current set of pause listeners 349 * for this animation. 350 */ addPauseListener(AnimatorPauseListener listener)351 public void addPauseListener(AnimatorPauseListener listener) { 352 if (mPauseListeners == null) { 353 mPauseListeners = new ArrayList<AnimatorPauseListener>(); 354 } 355 mPauseListeners.add(listener); 356 } 357 358 /** 359 * Removes a pause listener from the set listening to this animation. 360 * 361 * @param listener the listener to be removed from the current set of pause 362 * listeners for this animation. 363 */ removePauseListener(AnimatorPauseListener listener)364 public void removePauseListener(AnimatorPauseListener listener) { 365 if (mPauseListeners == null) { 366 return; 367 } 368 mPauseListeners.remove(listener); 369 if (mPauseListeners.size() == 0) { 370 mPauseListeners = null; 371 } 372 } 373 374 /** 375 * Removes all {@link #addListener(android.animation.Animator.AnimatorListener) listeners} 376 * and {@link #addPauseListener(android.animation.Animator.AnimatorPauseListener) 377 * pauseListeners} from this object. 378 */ removeAllListeners()379 public void removeAllListeners() { 380 if (mListeners != null) { 381 mListeners.clear(); 382 mListeners = null; 383 } 384 if (mPauseListeners != null) { 385 mPauseListeners.clear(); 386 mPauseListeners = null; 387 } 388 } 389 390 /** 391 * Return a mask of the configuration parameters for which this animator may change, requiring 392 * that it should be re-created from Resources. The default implementation returns whatever 393 * value was provided through setChangingConfigurations(int) or 0 by default. 394 * 395 * @return Returns a mask of the changing configuration parameters, as defined by 396 * {@link android.content.pm.ActivityInfo}. 397 * @see android.content.pm.ActivityInfo 398 * @hide 399 */ getChangingConfigurations()400 public @Config int getChangingConfigurations() { 401 return mChangingConfigurations; 402 } 403 404 /** 405 * Set a mask of the configuration parameters for which this animator may change, requiring 406 * that it be re-created from resource. 407 * 408 * @param configs A mask of the changing configuration parameters, as 409 * defined by {@link android.content.pm.ActivityInfo}. 410 * 411 * @see android.content.pm.ActivityInfo 412 * @hide 413 */ setChangingConfigurations(@onfig int configs)414 public void setChangingConfigurations(@Config int configs) { 415 mChangingConfigurations = configs; 416 } 417 418 /** 419 * Sets the changing configurations value to the union of the current changing configurations 420 * and the provided configs. 421 * This method is called while loading the animator. 422 * @hide 423 */ appendChangingConfigurations(@onfig int configs)424 public void appendChangingConfigurations(@Config int configs) { 425 mChangingConfigurations |= configs; 426 } 427 428 /** 429 * Return a {@link android.content.res.ConstantState} instance that holds the shared state of 430 * this Animator. 431 * <p> 432 * This constant state is used to create new instances of this animator when needed, instead 433 * of re-loading it from resources. Default implementation creates a new 434 * {@link AnimatorConstantState}. You can override this method to provide your custom logic or 435 * return null if you don't want this animator to be cached. 436 * 437 * @return The ConfigurationBoundResourceCache.BaseConstantState associated to this Animator. 438 * @see android.content.res.ConstantState 439 * @see #clone() 440 * @hide 441 */ createConstantState()442 public ConstantState<Animator> createConstantState() { 443 return new AnimatorConstantState(this); 444 } 445 446 @Override clone()447 public Animator clone() { 448 try { 449 final Animator anim = (Animator) super.clone(); 450 if (mListeners != null) { 451 anim.mListeners = new ArrayList<AnimatorListener>(mListeners); 452 } 453 if (mPauseListeners != null) { 454 anim.mPauseListeners = new ArrayList<AnimatorPauseListener>(mPauseListeners); 455 } 456 anim.mCachedList.set(null); 457 anim.mStartListenersCalled = false; 458 return anim; 459 } catch (CloneNotSupportedException e) { 460 throw new AssertionError(); 461 } 462 } 463 464 /** 465 * This method tells the object to use appropriate information to extract 466 * starting values for the animation. For example, a AnimatorSet object will pass 467 * this call to its child objects to tell them to set up the values. A 468 * ObjectAnimator object will use the information it has about its target object 469 * and PropertyValuesHolder objects to get the start values for its properties. 470 * A ValueAnimator object will ignore the request since it does not have enough 471 * information (such as a target object) to gather these values. 472 */ setupStartValues()473 public void setupStartValues() { 474 } 475 476 /** 477 * This method tells the object to use appropriate information to extract 478 * ending values for the animation. For example, a AnimatorSet object will pass 479 * this call to its child objects to tell them to set up the values. A 480 * ObjectAnimator object will use the information it has about its target object 481 * and PropertyValuesHolder objects to get the start values for its properties. 482 * A ValueAnimator object will ignore the request since it does not have enough 483 * information (such as a target object) to gather these values. 484 */ setupEndValues()485 public void setupEndValues() { 486 } 487 488 /** 489 * Sets the target object whose property will be animated by this animation. Not all subclasses 490 * operate on target objects (for example, {@link ValueAnimator}, but this method 491 * is on the superclass for the convenience of dealing generically with those subclasses 492 * that do handle targets. 493 * <p> 494 * <strong>Note:</strong> The target is stored as a weak reference internally to avoid leaking 495 * resources by having animators directly reference old targets. Therefore, you should 496 * ensure that animator targets always have a hard reference elsewhere. 497 * 498 * @param target The object being animated 499 */ setTarget(@ullable Object target)500 public void setTarget(@Nullable Object target) { 501 } 502 503 // Hide reverse() and canReverse() for now since reverse() only work for simple 504 // cases, like we don't support sequential, neither startDelay. 505 // TODO: make reverse() works for all the Animators. 506 /** 507 * @hide 508 */ canReverse()509 public boolean canReverse() { 510 return false; 511 } 512 513 /** 514 * @hide 515 */ 516 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) reverse()517 public void reverse() { 518 throw new IllegalStateException("Reverse is not supported"); 519 } 520 521 // Pulse an animation frame into the animation. pulseAnimationFrame(long frameTime)522 boolean pulseAnimationFrame(long frameTime) { 523 // TODO: Need to find a better signal than this. There's a bug in SystemUI that's preventing 524 // returning !isStarted() from working. 525 return false; 526 } 527 528 /** 529 * Internal use only. 530 * This call starts the animation in regular or reverse direction without requiring them to 531 * register frame callbacks. The caller will be responsible for all the subsequent animation 532 * pulses. Specifically, the caller needs to call doAnimationFrame(...) for the animation on 533 * every frame. 534 * 535 * @param inReverse whether the animation should play in reverse direction 536 */ startWithoutPulsing(boolean inReverse)537 void startWithoutPulsing(boolean inReverse) { 538 if (inReverse) { 539 reverse(); 540 } else { 541 start(); 542 } 543 } 544 545 /** 546 * Internal use only. 547 * Skips the animation value to end/start, depending on whether the play direction is forward 548 * or backward. 549 * 550 * @param inReverse whether the end value is based on a reverse direction. If yes, this is 551 * equivalent to skip to start value in a forward playing direction. 552 */ skipToEndValue(boolean inReverse)553 void skipToEndValue(boolean inReverse) {} 554 555 /** 556 * Internal use only. 557 * 558 * Returns whether the animation has start/end values setup. For most of the animations, this 559 * should always be true. For ObjectAnimators, the start values are setup in the initialization 560 * of the animation. 561 */ isInitialized()562 boolean isInitialized() { 563 return true; 564 } 565 566 /** 567 * Internal use only. Changes the value of the animator as if currentPlayTime has passed since 568 * the start of the animation. Therefore, currentPlayTime includes the start delay, and any 569 * repetition. lastPlayTime is similar and is used to calculate how many repeats have been 570 * done between the two times. 571 */ animateValuesInRange(long currentPlayTime, long lastPlayTime)572 void animateValuesInRange(long currentPlayTime, long lastPlayTime) {} 573 574 /** 575 * Internal use only. This animates any animation that has ended since lastPlayTime. 576 * If an animation hasn't been finished, no change will be made. 577 */ animateSkipToEnds(long currentPlayTime, long lastPlayTime)578 void animateSkipToEnds(long currentPlayTime, long lastPlayTime) {} 579 580 /** 581 * Internal use only. Adds all start times (after delay) to and end times to times. 582 * The value must include offset. 583 */ getStartAndEndTimes(LongArray times, long offset)584 void getStartAndEndTimes(LongArray times, long offset) { 585 long startTime = offset + getStartDelay(); 586 if (times.indexOf(startTime) < 0) { 587 times.add(startTime); 588 } 589 long duration = getTotalDuration(); 590 if (duration != DURATION_INFINITE) { 591 long endTime = duration + offset; 592 if (times.indexOf(endTime) < 0) { 593 times.add(endTime); 594 } 595 } 596 } 597 598 /** 599 * Calls notification for each AnimatorListener. 600 * 601 * @param notification The notification method to call on each listener. 602 * @param isReverse When this is used with start/end, this is the isReverse parameter. For 603 * other calls, this is ignored. 604 */ notifyListeners( AnimatorCaller<AnimatorListener, Animator> notification, boolean isReverse )605 void notifyListeners( 606 AnimatorCaller<AnimatorListener, Animator> notification, 607 boolean isReverse 608 ) { 609 callOnList(mListeners, notification, this, isReverse); 610 } 611 612 /** 613 * Call pause/resume on each AnimatorPauseListener. 614 * 615 * @param notification Either ON_PAUSE or ON_RESUME to call onPause or onResume on each 616 * listener. 617 */ notifyPauseListeners(AnimatorCaller<AnimatorPauseListener, Animator> notification)618 void notifyPauseListeners(AnimatorCaller<AnimatorPauseListener, Animator> notification) { 619 callOnList(mPauseListeners, notification, this, false); 620 } 621 notifyStartListeners(boolean isReversing)622 void notifyStartListeners(boolean isReversing) { 623 boolean startListenersCalled = mStartListenersCalled; 624 mStartListenersCalled = true; 625 if (mListeners != null && !startListenersCalled) { 626 notifyListeners(AnimatorCaller.ON_START, isReversing); 627 } 628 } 629 notifyEndListeners(boolean isReversing)630 void notifyEndListeners(boolean isReversing) { 631 boolean startListenersCalled = mStartListenersCalled; 632 mStartListenersCalled = false; 633 if (mListeners != null && startListenersCalled) { 634 notifyListeners(AnimatorCaller.ON_END, isReversing); 635 } 636 } 637 638 /** 639 * Calls <code>call</code> for every item in <code>list</code> with <code>animator</code> and 640 * <code>isReverse</code> as parameters. 641 * 642 * @param list The list of items to make calls on. 643 * @param call The method to call for each item in list. 644 * @param animator The animator parameter of call. 645 * @param isReverse The isReverse parameter of call. 646 * @param <T> The item type of list 647 * @param <A> The Animator type of animator. 648 */ callOnList( ArrayList<T> list, AnimatorCaller<T, A> call, A animator, boolean isReverse )649 <T, A> void callOnList( 650 ArrayList<T> list, 651 AnimatorCaller<T, A> call, 652 A animator, 653 boolean isReverse 654 ) { 655 int size = list == null ? 0 : list.size(); 656 if (size > 0) { 657 // Try to reuse mCacheList to store the items of list. 658 Object[] array = mCachedList.getAndSet(null); 659 if (array == null || array.length < size) { 660 array = new Object[size]; 661 } 662 list.toArray(array); 663 for (int i = 0; i < size; i++) { 664 //noinspection unchecked 665 T item = (T) array[i]; 666 call.call(item, animator, isReverse); 667 array[i] = null; 668 } 669 // Store it for the next call so we can reuse this array, if needed. 670 mCachedList.compareAndSet(null, array); 671 } 672 } 673 674 /** 675 * <p>An animation listener receives notifications from an animation. 676 * Notifications indicate animation related events, such as the end or the 677 * repetition of the animation.</p> 678 */ 679 public static interface AnimatorListener { 680 681 /** 682 * <p>Notifies the start of the animation as well as the animation's overall play direction. 683 * This method's default behavior is to call {@link #onAnimationStart(Animator)}. This 684 * method can be overridden, though not required, to get the additional play direction info 685 * when an animation starts. Skipping calling super when overriding this method results in 686 * {@link #onAnimationStart(Animator)} not getting called. 687 * 688 * @param animation The started animation. 689 * @param isReverse Whether the animation is playing in reverse. 690 */ onAnimationStart(@onNull Animator animation, boolean isReverse)691 default void onAnimationStart(@NonNull Animator animation, boolean isReverse) { 692 onAnimationStart(animation); 693 } 694 695 /** 696 * <p>Notifies the end of the animation. This callback is not invoked 697 * for animations with repeat count set to INFINITE.</p> 698 * 699 * <p>This method's default behavior is to call {@link #onAnimationEnd(Animator)}. This 700 * method can be overridden, though not required, to get the additional play direction info 701 * when an animation ends. Skipping calling super when overriding this method results in 702 * {@link #onAnimationEnd(Animator)} not getting called. 703 * 704 * @param animation The animation which reached its end. 705 * @param isReverse Whether the animation is playing in reverse. 706 */ onAnimationEnd(@onNull Animator animation, boolean isReverse)707 default void onAnimationEnd(@NonNull Animator animation, boolean isReverse) { 708 onAnimationEnd(animation); 709 } 710 711 /** 712 * <p>Notifies the start of the animation.</p> 713 * 714 * @param animation The started animation. 715 */ onAnimationStart(@onNull Animator animation)716 void onAnimationStart(@NonNull Animator animation); 717 718 /** 719 * <p>Notifies the end of the animation. This callback is not invoked 720 * for animations with repeat count set to INFINITE.</p> 721 * 722 * @param animation The animation which reached its end. 723 */ onAnimationEnd(@onNull Animator animation)724 void onAnimationEnd(@NonNull Animator animation); 725 726 /** 727 * <p>Notifies the cancellation of the animation. This callback is not invoked 728 * for animations with repeat count set to INFINITE.</p> 729 * 730 * @param animation The animation which was canceled. 731 */ onAnimationCancel(@onNull Animator animation)732 void onAnimationCancel(@NonNull Animator animation); 733 734 /** 735 * <p>Notifies the repetition of the animation.</p> 736 * 737 * @param animation The animation which was repeated. 738 */ onAnimationRepeat(@onNull Animator animation)739 void onAnimationRepeat(@NonNull Animator animation); 740 } 741 742 /** 743 * A pause listener receives notifications from an animation when the 744 * animation is {@link #pause() paused} or {@link #resume() resumed}. 745 * 746 * @see #addPauseListener(AnimatorPauseListener) 747 */ 748 public static interface AnimatorPauseListener { 749 /** 750 * <p>Notifies that the animation was paused.</p> 751 * 752 * @param animation The animaton being paused. 753 * @see #pause() 754 */ onAnimationPause(@onNull Animator animation)755 void onAnimationPause(@NonNull Animator animation); 756 757 /** 758 * <p>Notifies that the animation was resumed, after being 759 * previously paused.</p> 760 * 761 * @param animation The animation being resumed. 762 * @see #resume() 763 */ onAnimationResume(@onNull Animator animation)764 void onAnimationResume(@NonNull Animator animation); 765 } 766 767 /** 768 * <p>Whether or not the Animator is allowed to run asynchronously off of 769 * the UI thread. This is a hint that informs the Animator that it is 770 * OK to run the animation off-thread, however the Animator may decide 771 * that it must run the animation on the UI thread anyway. 772 * 773 * <p>Regardless of whether or not the animation runs asynchronously, all 774 * listener callbacks will be called on the UI thread.</p> 775 * 776 * <p>To be able to use this hint the following must be true:</p> 777 * <ol> 778 * <li>The animator is immutable while {@link #isStarted()} is true. Requests 779 * to change duration, delay, etc... may be ignored.</li> 780 * <li>Lifecycle callback events may be asynchronous. Events such as 781 * {@link Animator.AnimatorListener#onAnimationEnd(Animator)} or 782 * {@link Animator.AnimatorListener#onAnimationRepeat(Animator)} may end up delayed 783 * as they must be posted back to the UI thread, and any actions performed 784 * by those callbacks (such as starting new animations) will not happen 785 * in the same frame.</li> 786 * <li>State change requests ({@link #cancel()}, {@link #end()}, {@link #reverse()}, etc...) 787 * may be asynchronous. It is guaranteed that all state changes that are 788 * performed on the UI thread in the same frame will be applied as a single 789 * atomic update, however that frame may be the current frame, 790 * the next frame, or some future frame. This will also impact the observed 791 * state of the Animator. For example, {@link #isStarted()} may still return true 792 * after a call to {@link #end()}. Using the lifecycle callbacks is preferred over 793 * queries to {@link #isStarted()}, {@link #isRunning()}, and {@link #isPaused()} 794 * for this reason.</li> 795 * </ol> 796 * @hide 797 */ setAllowRunningAsynchronously(boolean mayRunAsync)798 public void setAllowRunningAsynchronously(boolean mayRunAsync) { 799 // It is up to subclasses to support this, if they can. 800 } 801 802 /** 803 * Creates a {@link ConstantState} which holds changing configurations information associated 804 * with the given Animator. 805 * <p> 806 * When {@link #newInstance()} is called, default implementation clones the Animator. 807 */ 808 private static class AnimatorConstantState extends ConstantState<Animator> { 809 810 final Animator mAnimator; 811 @Config int mChangingConf; 812 AnimatorConstantState(Animator animator)813 public AnimatorConstantState(Animator animator) { 814 mAnimator = animator; 815 // ensure a reference back to here so that constante state is not gc'ed. 816 mAnimator.mConstantState = this; 817 mChangingConf = mAnimator.getChangingConfigurations(); 818 } 819 820 @Override getChangingConfigurations()821 public @Config int getChangingConfigurations() { 822 return mChangingConf; 823 } 824 825 @Override newInstance()826 public Animator newInstance() { 827 final Animator clone = mAnimator.clone(); 828 clone.mConstantState = this; 829 return clone; 830 } 831 } 832 833 /** 834 * Internally used by {@link #callOnList(ArrayList, AnimatorCaller, Object, boolean)} to 835 * make a call on all children of a list. This can be for start, stop, pause, cancel, update, 836 * etc notifications. 837 * 838 * @param <T> The type of listener to make the call on 839 * @param <A> The type of animator that is passed as a parameter 840 */ 841 interface AnimatorCaller<T, A> { call(T listener, A animator, boolean isReverse)842 void call(T listener, A animator, boolean isReverse); 843 844 AnimatorCaller<AnimatorListener, Animator> ON_START = AnimatorListener::onAnimationStart; 845 AnimatorCaller<AnimatorListener, Animator> ON_END = AnimatorListener::onAnimationEnd; 846 AnimatorCaller<AnimatorListener, Animator> ON_CANCEL = 847 (listener, animator, isReverse) -> listener.onAnimationCancel(animator); 848 AnimatorCaller<AnimatorListener, Animator> ON_REPEAT = 849 (listener, animator, isReverse) -> listener.onAnimationRepeat(animator); 850 AnimatorCaller<AnimatorPauseListener, Animator> ON_PAUSE = 851 (listener, animator, isReverse) -> listener.onAnimationPause(animator); 852 AnimatorCaller<AnimatorPauseListener, Animator> ON_RESUME = 853 (listener, animator, isReverse) -> listener.onAnimationResume(animator); 854 AnimatorCaller<ValueAnimator.AnimatorUpdateListener, ValueAnimator> ON_UPDATE = 855 (listener, animator, isReverse) -> listener.onAnimationUpdate(animator); 856 } 857 } 858