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