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