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