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