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