1 /* 2 * Copyright (C) 2006 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.view.animation; 18 19 import android.annotation.AnimRes; 20 import android.annotation.ColorInt; 21 import android.annotation.InterpolatorRes; 22 import android.compat.annotation.UnsupportedAppUsage; 23 import android.content.Context; 24 import android.content.res.TypedArray; 25 import android.graphics.RectF; 26 import android.os.Build; 27 import android.os.Handler; 28 import android.os.SystemProperties; 29 import android.util.AttributeSet; 30 import android.util.TypedValue; 31 import android.view.WindowInsets; 32 33 import dalvik.system.CloseGuard; 34 35 /** 36 * Abstraction for an Animation that can be applied to Views, Surfaces, or 37 * other objects. See the {@link android.view.animation animation package 38 * description file}. 39 */ 40 public abstract class Animation implements Cloneable { 41 /** 42 * Repeat the animation indefinitely. 43 */ 44 public static final int INFINITE = -1; 45 46 /** 47 * When the animation reaches the end and the repeat count is INFINTE_REPEAT 48 * or a positive value, the animation restarts from the beginning. 49 */ 50 public static final int RESTART = 1; 51 52 /** 53 * When the animation reaches the end and the repeat count is INFINTE_REPEAT 54 * or a positive value, the animation plays backward (and then forward again). 55 */ 56 public static final int REVERSE = 2; 57 58 /** 59 * Can be used as the start time to indicate the start time should be the current 60 * time when {@link #getTransformation(long, Transformation)} is invoked for the 61 * first animation frame. This can is useful for short animations. 62 */ 63 public static final int START_ON_FIRST_FRAME = -1; 64 65 /** 66 * The specified dimension is an absolute number of pixels. 67 */ 68 public static final int ABSOLUTE = 0; 69 70 /** 71 * The specified dimension holds a float and should be multiplied by the 72 * height or width of the object being animated. 73 */ 74 public static final int RELATIVE_TO_SELF = 1; 75 76 /** 77 * The specified dimension holds a float and should be multiplied by the 78 * height or width of the parent of the object being animated. 79 */ 80 public static final int RELATIVE_TO_PARENT = 2; 81 82 /** 83 * Requests that the content being animated be kept in its current Z 84 * order. 85 */ 86 public static final int ZORDER_NORMAL = 0; 87 88 /** 89 * Requests that the content being animated be forced on top of all other 90 * content for the duration of the animation. 91 */ 92 public static final int ZORDER_TOP = 1; 93 94 /** 95 * Requests that the content being animated be forced under all other 96 * content for the duration of the animation. 97 */ 98 public static final int ZORDER_BOTTOM = -1; 99 100 // Use a preload holder to isolate static initialization into inner class, which allows 101 // Animation and its subclasses to be compile-time initialized. 102 private static class NoImagePreloadHolder { 103 public static final boolean USE_CLOSEGUARD 104 = SystemProperties.getBoolean("log.closeguard.Animation", false); 105 } 106 107 /** 108 * Set by {@link #getTransformation(long, Transformation)} when the animation ends. 109 */ 110 boolean mEnded = false; 111 112 /** 113 * Set by {@link #getTransformation(long, Transformation)} when the animation starts. 114 */ 115 boolean mStarted = false; 116 117 /** 118 * Set by {@link #getTransformation(long, Transformation)} when the animation repeats 119 * in REVERSE mode. 120 */ 121 boolean mCycleFlip = false; 122 123 /** 124 * This value must be set to true by {@link #initialize(int, int, int, int)}. It 125 * indicates the animation was successfully initialized and can be played. 126 */ 127 boolean mInitialized = false; 128 129 /** 130 * Indicates whether the animation transformation should be applied before the 131 * animation starts. The value of this variable is only relevant if mFillEnabled is true; 132 * otherwise it is assumed to be true. 133 */ 134 boolean mFillBefore = true; 135 136 /** 137 * Indicates whether the animation transformation should be applied after the 138 * animation ends. 139 */ 140 boolean mFillAfter = false; 141 142 /** 143 * Indicates whether fillBefore should be taken into account. 144 */ 145 boolean mFillEnabled = false; 146 147 /** 148 * The time in milliseconds at which the animation must start; 149 */ 150 long mStartTime = -1; 151 152 /** 153 * The delay in milliseconds after which the animation must start. When the 154 * start offset is > 0, the start time of the animation is startTime + startOffset. 155 */ 156 long mStartOffset; 157 158 /** 159 * The duration of one animation cycle in milliseconds. 160 */ 161 long mDuration; 162 163 /** 164 * The number of times the animation must repeat. By default, an animation repeats 165 * indefinitely. 166 */ 167 int mRepeatCount = 0; 168 169 /** 170 * Indicates how many times the animation was repeated. 171 */ 172 int mRepeated = 0; 173 174 /** 175 * The behavior of the animation when it repeats. The repeat mode is either 176 * {@link #RESTART} or {@link #REVERSE}. 177 * 178 */ 179 int mRepeatMode = RESTART; 180 181 /** 182 * The interpolator used by the animation to smooth the movement. 183 */ 184 Interpolator mInterpolator; 185 186 /** 187 * An animation listener to be notified when the animation starts, ends or repeats. 188 */ 189 // If you need to chain the AnimationListener, wrap the existing Animation into an AnimationSet 190 // and add your new listener to that set 191 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 117519981) 192 private AnimationListener mListener; 193 194 /** 195 * Desired Z order mode during animation. 196 */ 197 private int mZAdjustment; 198 199 /** 200 * The desired color of the backdrop to show behind the animation. 201 */ 202 private int mBackdropColor; 203 204 /** 205 * scalefactor to apply to pivot points, etc. during animation. Subclasses retrieve the 206 * value via getScaleFactor(). 207 */ 208 private float mScaleFactor = 1f; 209 210 private boolean mShowWallpaper; 211 private boolean mHasRoundedCorners; 212 213 /** 214 * Whether to show a background behind the windows during the animation. 215 * @see #getShowBackdrop() 216 * @see #setShowBackdrop(boolean) 217 */ 218 private boolean mShowBackdrop; 219 220 private boolean mMore = true; 221 private boolean mOneMoreTime = true; 222 223 @UnsupportedAppUsage 224 RectF mPreviousRegion = new RectF(); 225 @UnsupportedAppUsage 226 RectF mRegion = new RectF(); 227 @UnsupportedAppUsage 228 Transformation mTransformation = new Transformation(); 229 @UnsupportedAppUsage 230 Transformation mPreviousTransformation = new Transformation(); 231 232 private final CloseGuard guard = CloseGuard.get(); 233 234 private Handler mListenerHandler; 235 private Runnable mOnStart; 236 private Runnable mOnRepeat; 237 private Runnable mOnEnd; 238 239 /** 240 * Creates a new animation with a duration of 0ms, the default interpolator, with 241 * fillBefore set to true and fillAfter set to false 242 */ Animation()243 public Animation() { 244 ensureInterpolator(); 245 } 246 247 /** 248 * Creates a new animation whose parameters come from the specified context and 249 * attributes set. 250 * 251 * @param context the application environment 252 * @param attrs the set of attributes holding the animation parameters 253 */ Animation(Context context, AttributeSet attrs)254 public Animation(Context context, AttributeSet attrs) { 255 TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Animation); 256 257 setDuration((long) a.getInt(com.android.internal.R.styleable.Animation_duration, 0)); 258 setStartOffset((long) a.getInt(com.android.internal.R.styleable.Animation_startOffset, 0)); 259 260 setFillEnabled(a.getBoolean(com.android.internal.R.styleable.Animation_fillEnabled, mFillEnabled)); 261 setFillBefore(a.getBoolean(com.android.internal.R.styleable.Animation_fillBefore, mFillBefore)); 262 setFillAfter(a.getBoolean(com.android.internal.R.styleable.Animation_fillAfter, mFillAfter)); 263 264 setRepeatCount(a.getInt(com.android.internal.R.styleable.Animation_repeatCount, mRepeatCount)); 265 setRepeatMode(a.getInt(com.android.internal.R.styleable.Animation_repeatMode, RESTART)); 266 267 setZAdjustment(a.getInt(com.android.internal.R.styleable.Animation_zAdjustment, ZORDER_NORMAL)); 268 269 setBackdropColor(a.getInt(com.android.internal.R.styleable.Animation_backdropColor, 0)); 270 271 setDetachWallpaper( 272 a.getBoolean(com.android.internal.R.styleable.Animation_detachWallpaper, false)); 273 setShowWallpaper( 274 a.getBoolean(com.android.internal.R.styleable.Animation_showWallpaper, false)); 275 setHasRoundedCorners( 276 a.getBoolean(com.android.internal.R.styleable.Animation_hasRoundedCorners, false)); 277 setShowBackdrop( 278 a.getBoolean(com.android.internal.R.styleable.Animation_showBackdrop, false)); 279 280 final int resID = a.getResourceId(com.android.internal.R.styleable.Animation_interpolator, 0); 281 282 a.recycle(); 283 284 if (resID > 0) { 285 setInterpolator(context, resID); 286 } 287 288 ensureInterpolator(); 289 } 290 291 @Override clone()292 protected Animation clone() throws CloneNotSupportedException { 293 final Animation animation = (Animation) super.clone(); 294 animation.mPreviousRegion = new RectF(); 295 animation.mRegion = new RectF(); 296 animation.mTransformation = new Transformation(); 297 animation.mPreviousTransformation = new Transformation(); 298 return animation; 299 } 300 301 /** 302 * Reset the initialization state of this animation. 303 * 304 * @see #initialize(int, int, int, int) 305 */ reset()306 public void reset() { 307 mPreviousRegion.setEmpty(); 308 mPreviousTransformation.clear(); 309 mInitialized = false; 310 mCycleFlip = false; 311 mRepeated = 0; 312 mMore = true; 313 mOneMoreTime = true; 314 mListenerHandler = null; 315 } 316 317 /** 318 * Cancel the animation. Cancelling an animation invokes the animation 319 * listener, if set, to notify the end of the animation. 320 * 321 * If you cancel an animation manually, you must call {@link #reset()} 322 * before starting the animation again. 323 * 324 * @see #reset() 325 * @see #start() 326 * @see #startNow() 327 */ cancel()328 public void cancel() { 329 if (mStarted && !mEnded) { 330 fireAnimationEnd(); 331 mEnded = true; 332 guard.close(); 333 } 334 // Make sure we move the animation to the end 335 mStartTime = Long.MIN_VALUE; 336 mMore = mOneMoreTime = false; 337 } 338 339 /** 340 * @hide 341 */ 342 @UnsupportedAppUsage detach()343 public void detach() { 344 if (mStarted && !mEnded) { 345 mEnded = true; 346 guard.close(); 347 fireAnimationEnd(); 348 } 349 } 350 351 /** 352 * Whether or not the animation has been initialized. 353 * 354 * @return Has this animation been initialized. 355 * @see #initialize(int, int, int, int) 356 */ isInitialized()357 public boolean isInitialized() { 358 return mInitialized; 359 } 360 361 /** 362 * Initialize this animation with the dimensions of the object being 363 * animated as well as the objects parents. (This is to support animation 364 * sizes being specified relative to these dimensions.) 365 * 366 * <p>Objects that interpret Animations should call this method when 367 * the sizes of the object being animated and its parent are known, and 368 * before calling {@link #getTransformation}. 369 * 370 * 371 * @param width Width of the object being animated 372 * @param height Height of the object being animated 373 * @param parentWidth Width of the animated object's parent 374 * @param parentHeight Height of the animated object's parent 375 */ initialize(int width, int height, int parentWidth, int parentHeight)376 public void initialize(int width, int height, int parentWidth, int parentHeight) { 377 reset(); 378 mInitialized = true; 379 } 380 381 /** 382 * Sets the handler used to invoke listeners. 383 * 384 * @hide 385 */ setListenerHandler(Handler handler)386 public void setListenerHandler(Handler handler) { 387 if (mListenerHandler == null) { 388 mOnStart = new Runnable() { 389 public void run() { 390 dispatchAnimationStart(); 391 } 392 }; 393 mOnRepeat = new Runnable() { 394 public void run() { 395 dispatchAnimationRepeat(); 396 } 397 }; 398 mOnEnd = new Runnable() { 399 public void run() { 400 dispatchAnimationEnd(); 401 } 402 }; 403 } 404 mListenerHandler = handler; 405 } 406 407 /** 408 * Sets the acceleration curve for this animation. The interpolator is loaded as 409 * a resource from the specified context. 410 * 411 * @param context The application environment 412 * @param resID The resource identifier of the interpolator to load 413 * @attr ref android.R.styleable#Animation_interpolator 414 */ setInterpolator(Context context, @AnimRes @InterpolatorRes int resID)415 public void setInterpolator(Context context, @AnimRes @InterpolatorRes int resID) { 416 setInterpolator(AnimationUtils.loadInterpolator(context, resID)); 417 } 418 419 /** 420 * Sets the acceleration curve for this animation. Defaults to a linear 421 * interpolation. 422 * 423 * @param i The interpolator which defines the acceleration curve 424 * @attr ref android.R.styleable#Animation_interpolator 425 */ setInterpolator(Interpolator i)426 public void setInterpolator(Interpolator i) { 427 mInterpolator = i; 428 } 429 430 /** 431 * When this animation should start relative to the start time. This is most 432 * useful when composing complex animations using an {@link AnimationSet } 433 * where some of the animations components start at different times. 434 * 435 * @param startOffset When this Animation should start, in milliseconds from 436 * the start time of the root AnimationSet. 437 * @attr ref android.R.styleable#Animation_startOffset 438 */ setStartOffset(long startOffset)439 public void setStartOffset(long startOffset) { 440 mStartOffset = startOffset; 441 } 442 443 /** 444 * How long this animation should last. The duration cannot be negative. 445 * 446 * @param durationMillis Duration in milliseconds 447 * 448 * @throws java.lang.IllegalArgumentException if the duration is < 0 449 * 450 * @attr ref android.R.styleable#Animation_duration 451 */ setDuration(long durationMillis)452 public void setDuration(long durationMillis) { 453 if (durationMillis < 0) { 454 throw new IllegalArgumentException("Animation duration cannot be negative"); 455 } 456 mDuration = durationMillis; 457 } 458 459 /** 460 * Ensure that the duration that this animation will run is not longer 461 * than <var>durationMillis</var>. In addition to adjusting the duration 462 * itself, this ensures that the repeat count also will not make it run 463 * longer than the given time. 464 * 465 * @param durationMillis The maximum duration the animation is allowed 466 * to run. 467 */ restrictDuration(long durationMillis)468 public void restrictDuration(long durationMillis) { 469 // If we start after the duration, then we just won't run. 470 if (mStartOffset > durationMillis) { 471 mStartOffset = durationMillis; 472 mDuration = 0; 473 mRepeatCount = 0; 474 return; 475 } 476 477 long dur = mDuration + mStartOffset; 478 if (dur > durationMillis) { 479 mDuration = durationMillis-mStartOffset; 480 dur = durationMillis; 481 } 482 // If the duration is 0 or less, then we won't run. 483 if (mDuration <= 0) { 484 mDuration = 0; 485 mRepeatCount = 0; 486 return; 487 } 488 // Reduce the number of repeats to keep below the maximum duration. 489 // The comparison between mRepeatCount and duration is to catch 490 // overflows after multiplying them. 491 if (mRepeatCount < 0 || mRepeatCount > durationMillis 492 || (dur*mRepeatCount) > durationMillis) { 493 // Figure out how many times to do the animation. Subtract 1 since 494 // repeat count is the number of times to repeat so 0 runs once. 495 mRepeatCount = (int)(durationMillis/dur) - 1; 496 if (mRepeatCount < 0) { 497 mRepeatCount = 0; 498 } 499 } 500 } 501 502 /** 503 * How much to scale the duration by. 504 * 505 * @param scale The amount to scale the duration. 506 */ scaleCurrentDuration(float scale)507 public void scaleCurrentDuration(float scale) { 508 mDuration = (long) (mDuration * scale); 509 mStartOffset = (long) (mStartOffset * scale); 510 } 511 512 /** 513 * When this animation should start. When the start time is set to 514 * {@link #START_ON_FIRST_FRAME}, the animation will start the first time 515 * {@link #getTransformation(long, Transformation)} is invoked. The time passed 516 * to this method should be obtained by calling 517 * {@link AnimationUtils#currentAnimationTimeMillis()} instead of 518 * {@link System#currentTimeMillis()}. 519 * 520 * @param startTimeMillis the start time in milliseconds 521 */ setStartTime(long startTimeMillis)522 public void setStartTime(long startTimeMillis) { 523 mStartTime = startTimeMillis; 524 mStarted = mEnded = false; 525 mCycleFlip = false; 526 mRepeated = 0; 527 mMore = true; 528 } 529 530 /** 531 * Convenience method to start the animation the first time 532 * {@link #getTransformation(long, Transformation)} is invoked. 533 */ start()534 public void start() { 535 setStartTime(-1); 536 } 537 538 /** 539 * Convenience method to start the animation at the current time in 540 * milliseconds. 541 */ startNow()542 public void startNow() { 543 setStartTime(AnimationUtils.currentAnimationTimeMillis()); 544 } 545 546 /** 547 * Defines what this animation should do when it reaches the end. This 548 * setting is applied only when the repeat count is either greater than 549 * 0 or {@link #INFINITE}. Defaults to {@link #RESTART}. 550 * 551 * @param repeatMode {@link #RESTART} or {@link #REVERSE} 552 * @attr ref android.R.styleable#Animation_repeatMode 553 */ setRepeatMode(int repeatMode)554 public void setRepeatMode(int repeatMode) { 555 mRepeatMode = repeatMode; 556 } 557 558 /** 559 * Sets how many times the animation should be repeated. If the repeat 560 * count is 0, the animation is never repeated. If the repeat count is 561 * greater than 0 or {@link #INFINITE}, the repeat mode will be taken 562 * into account. The repeat count is 0 by default. 563 * 564 * @param repeatCount the number of times the animation should be repeated 565 * @attr ref android.R.styleable#Animation_repeatCount 566 */ setRepeatCount(int repeatCount)567 public void setRepeatCount(int repeatCount) { 568 if (repeatCount < 0) { 569 repeatCount = INFINITE; 570 } 571 mRepeatCount = repeatCount; 572 } 573 574 /** 575 * If fillEnabled is true, this animation will apply the value of fillBefore. 576 * 577 * @return true if the animation will take fillBefore into account 578 * @attr ref android.R.styleable#Animation_fillEnabled 579 */ isFillEnabled()580 public boolean isFillEnabled() { 581 return mFillEnabled; 582 } 583 584 /** 585 * If fillEnabled is true, the animation will apply the value of fillBefore. 586 * Otherwise, fillBefore is ignored and the animation 587 * transformation is always applied until the animation ends. 588 * 589 * @param fillEnabled true if the animation should take the value of fillBefore into account 590 * @attr ref android.R.styleable#Animation_fillEnabled 591 * 592 * @see #setFillBefore(boolean) 593 * @see #setFillAfter(boolean) 594 */ setFillEnabled(boolean fillEnabled)595 public void setFillEnabled(boolean fillEnabled) { 596 mFillEnabled = fillEnabled; 597 } 598 599 /** 600 * If fillBefore is true, this animation will apply its transformation 601 * before the start time of the animation. Defaults to true if 602 * {@link #setFillEnabled(boolean)} is not set to true. 603 * Note that this applies when using an {@link 604 * android.view.animation.AnimationSet AnimationSet} to chain 605 * animations. The transformation is not applied before the AnimationSet 606 * itself starts. 607 * 608 * @param fillBefore true if the animation should apply its transformation before it starts 609 * @attr ref android.R.styleable#Animation_fillBefore 610 * 611 * @see #setFillEnabled(boolean) 612 */ setFillBefore(boolean fillBefore)613 public void setFillBefore(boolean fillBefore) { 614 mFillBefore = fillBefore; 615 } 616 617 /** 618 * If fillAfter is true, the transformation that this animation performed 619 * will persist when it is finished. Defaults to false if not set. 620 * Note that this applies to individual animations and when using an {@link 621 * android.view.animation.AnimationSet AnimationSet} to chain 622 * animations. 623 * 624 * @param fillAfter true if the animation should apply its transformation after it ends 625 * @attr ref android.R.styleable#Animation_fillAfter 626 * 627 * @see #setFillEnabled(boolean) 628 */ setFillAfter(boolean fillAfter)629 public void setFillAfter(boolean fillAfter) { 630 mFillAfter = fillAfter; 631 } 632 633 /** 634 * Set the Z ordering mode to use while running the animation. 635 * 636 * @param zAdjustment The desired mode, one of {@link #ZORDER_NORMAL}, 637 * {@link #ZORDER_TOP}, or {@link #ZORDER_BOTTOM}. 638 * @attr ref android.R.styleable#Animation_zAdjustment 639 */ setZAdjustment(int zAdjustment)640 public void setZAdjustment(int zAdjustment) { 641 mZAdjustment = zAdjustment; 642 } 643 644 /** 645 * Set background behind animation. 646 * 647 * @param bg The background color. If 0, no background. Currently must 648 * be black, with any desired alpha level. 649 * 650 * @deprecated None of window animations are running with background color. 651 * @see #setBackdropColor(int) for an alternative. 652 */ 653 @Deprecated setBackgroundColor(@olorInt int bg)654 public void setBackgroundColor(@ColorInt int bg) { 655 // The background color is not needed any more, do nothing. 656 } 657 658 /** 659 * The scale factor is set by the call to <code>getTransformation</code>. Overrides of 660 * {@link #getTransformation(long, Transformation, float)} will get this value 661 * directly. Overrides of {@link #applyTransformation(float, Transformation)} can 662 * call this method to get the value. 663 * 664 * @return float The scale factor that should be applied to pre-scaled values in 665 * an Animation such as the pivot points in {@link ScaleAnimation} and {@link RotateAnimation}. 666 */ getScaleFactor()667 protected float getScaleFactor() { 668 return mScaleFactor; 669 } 670 671 /** 672 * If detachWallpaper is true, and this is a window animation of a window 673 * that has a wallpaper background, then the window will be detached from 674 * the wallpaper while it runs. That is, the animation will only be applied 675 * to the window, and the wallpaper behind it will remain static. 676 * 677 * @param detachWallpaper true if the wallpaper should be detached from the animation 678 * @attr ref android.R.styleable#Animation_detachWallpaper 679 * 680 * @deprecated All window animations are running with detached wallpaper. 681 */ 682 @Deprecated setDetachWallpaper(boolean detachWallpaper)683 public void setDetachWallpaper(boolean detachWallpaper) { 684 } 685 686 /** 687 * If this animation is run as a window animation, this will make the wallpaper visible behind 688 * the animation. 689 * 690 * @param showWallpaper Whether the wallpaper should be shown during the animation. 691 * @attr ref android.R.styleable#Animation_detachWallpaper 692 * @hide 693 */ setShowWallpaper(boolean showWallpaper)694 public void setShowWallpaper(boolean showWallpaper) { 695 mShowWallpaper = showWallpaper; 696 } 697 698 /** 699 * If this is a window animation, the window will have rounded corners matching the display 700 * corner radius. 701 * 702 * @param hasRoundedCorners Whether the window should have rounded corners or not. 703 * @attr ref android.R.styleable#Animation_hasRoundedCorners 704 * @see com.android.internal.policy.ScreenDecorationsUtils#getWindowCornerRadius(Resources) 705 * @hide 706 */ setHasRoundedCorners(boolean hasRoundedCorners)707 public void setHasRoundedCorners(boolean hasRoundedCorners) { 708 mHasRoundedCorners = hasRoundedCorners; 709 } 710 711 /** 712 * If showBackdrop is {@code true} and this animation is applied on a window, then the windows 713 * in the animation will animate with the background associated with this window behind them. 714 * 715 * If no backdrop color is explicitly set, the backdrop's color comes from the 716 * {@link android.R.styleable#Theme_colorBackground} that is applied to this window through its 717 * theme. 718 * 719 * If multiple animating windows have showBackdrop set to {@code true} during an animation, 720 * the top most window with showBackdrop set to {@code true} and a valid background color 721 * takes precedence. 722 * 723 * @param showBackdrop Whether to show a background behind the windows during the animation. 724 * @attr ref android.R.styleable#Animation_showBackdrop 725 */ setShowBackdrop(boolean showBackdrop)726 public void setShowBackdrop(boolean showBackdrop) { 727 mShowBackdrop = showBackdrop; 728 } 729 730 /** 731 * Set the color to use for the backdrop shown behind the animating windows. 732 * 733 * Will only show the backdrop if showBackdrop was set to true. 734 * See {@link #setShowBackdrop(boolean)}. 735 * 736 * @param backdropColor The backdrop color. If 0, the backdrop color will not apply. 737 * @attr ref android.R.styleable#Animation_backdropColor 738 */ setBackdropColor(@olorInt int backdropColor)739 public void setBackdropColor(@ColorInt int backdropColor) { 740 mBackdropColor = backdropColor; 741 } 742 743 /** 744 * Gets the acceleration curve type for this animation. 745 * 746 * @return the {@link Interpolator} associated to this animation 747 * @attr ref android.R.styleable#Animation_interpolator 748 */ getInterpolator()749 public Interpolator getInterpolator() { 750 return mInterpolator; 751 } 752 753 /** 754 * When this animation should start. If the animation has not startet yet, 755 * this method might return {@link #START_ON_FIRST_FRAME}. 756 * 757 * @return the time in milliseconds when the animation should start or 758 * {@link #START_ON_FIRST_FRAME} 759 */ getStartTime()760 public long getStartTime() { 761 return mStartTime; 762 } 763 764 /** 765 * How long this animation should last 766 * 767 * @return the duration in milliseconds of the animation 768 * @attr ref android.R.styleable#Animation_duration 769 */ getDuration()770 public long getDuration() { 771 return mDuration; 772 } 773 774 /** 775 * When this animation should start, relative to StartTime 776 * 777 * @return the start offset in milliseconds 778 * @attr ref android.R.styleable#Animation_startOffset 779 */ getStartOffset()780 public long getStartOffset() { 781 return mStartOffset; 782 } 783 784 /** 785 * Defines what this animation should do when it reaches the end. 786 * 787 * @return either one of {@link #REVERSE} or {@link #RESTART} 788 * @attr ref android.R.styleable#Animation_repeatMode 789 */ getRepeatMode()790 public int getRepeatMode() { 791 return mRepeatMode; 792 } 793 794 /** 795 * Defines how many times the animation should repeat. The default value 796 * is 0. 797 * 798 * @return the number of times the animation should repeat, or {@link #INFINITE} 799 * @attr ref android.R.styleable#Animation_repeatCount 800 */ getRepeatCount()801 public int getRepeatCount() { 802 return mRepeatCount; 803 } 804 805 /** 806 * If fillBefore is true, this animation will apply its transformation 807 * before the start time of the animation. If fillBefore is false and 808 * {@link #isFillEnabled() fillEnabled} is true, the transformation will not be applied until 809 * the start time of the animation. 810 * 811 * @return true if the animation applies its transformation before it starts 812 * @attr ref android.R.styleable#Animation_fillBefore 813 */ getFillBefore()814 public boolean getFillBefore() { 815 return mFillBefore; 816 } 817 818 /** 819 * If fillAfter is true, this animation will apply its transformation 820 * after the end time of the animation. 821 * 822 * @return true if the animation applies its transformation after it ends 823 * @attr ref android.R.styleable#Animation_fillAfter 824 */ getFillAfter()825 public boolean getFillAfter() { 826 return mFillAfter; 827 } 828 829 /** 830 * Returns the Z ordering mode to use while running the animation as 831 * previously set by {@link #setZAdjustment}. 832 * 833 * @return Returns one of {@link #ZORDER_NORMAL}, 834 * {@link #ZORDER_TOP}, or {@link #ZORDER_BOTTOM}. 835 * @attr ref android.R.styleable#Animation_zAdjustment 836 */ getZAdjustment()837 public int getZAdjustment() { 838 return mZAdjustment; 839 } 840 841 /** 842 * Returns the background color behind the animation. 843 * 844 * @deprecated None of window animations are running with background color. 845 * @see #getBackdropColor() for an alternative. 846 */ 847 @Deprecated 848 @ColorInt getBackgroundColor()849 public int getBackgroundColor() { 850 return 0; 851 } 852 853 /** 854 * Return value of {@link #setDetachWallpaper(boolean)}. 855 * @attr ref android.R.styleable#Animation_detachWallpaper 856 * 857 * @deprecated All window animations are running with detached wallpaper. 858 */ 859 @Deprecated getDetachWallpaper()860 public boolean getDetachWallpaper() { 861 return true; 862 } 863 864 /** 865 * @return If run as a window animation, returns whether the wallpaper will be shown behind 866 * during the animation. 867 * @attr ref android.R.styleable#Animation_showWallpaper 868 * @hide 869 */ getShowWallpaper()870 public boolean getShowWallpaper() { 871 return mShowWallpaper; 872 } 873 874 /** 875 * @return if a window animation should have rounded corners or not. 876 * 877 * @attr ref android.R.styleable#Animation_hasRoundedCorners 878 * @hide 879 */ hasRoundedCorners()880 public boolean hasRoundedCorners() { 881 return mHasRoundedCorners; 882 } 883 884 /** 885 * @return the edges to which outsets should be applied if run as a windoow animation. 886 * 887 * @hide 888 */ 889 @WindowInsets.Side.InsetsSide getExtensionEdges()890 public int getExtensionEdges() { 891 return 0x0; 892 } 893 894 /** 895 * If showBackdrop is {@code true} and this animation is applied on a window, then the windows 896 * in the animation will animate with the background associated with this window behind them. 897 * 898 * If no backdrop color is explicitly set, the backdrop's color comes from the 899 * {@link android.R.styleable#Theme_colorBackground} that is applied to this window 900 * through its theme. 901 * 902 * If multiple animating windows have showBackdrop set to {@code true} during an animation, 903 * the top most window with showBackdrop set to {@code true} and a valid background color 904 * takes precedence. 905 * 906 * @return if a backdrop should be shown behind the animating windows. 907 * @attr ref android.R.styleable#Animation_showBackdrop 908 */ getShowBackdrop()909 public boolean getShowBackdrop() { 910 return mShowBackdrop; 911 } 912 913 /** 914 * Returns the background color to show behind the animating windows. 915 * 916 * Will only show the background if showBackdrop was set to true. 917 * See {@link #setShowBackdrop(boolean)}. 918 * 919 * @return The backdrop color. If 0, the backdrop color will not apply. 920 * @attr ref android.R.styleable#Animation_backdropColor 921 */ 922 @ColorInt getBackdropColor()923 public int getBackdropColor() { 924 return mBackdropColor; 925 } 926 927 /** 928 * <p>Indicates whether or not this animation will affect the transformation 929 * matrix. For instance, a fade animation will not affect the matrix whereas 930 * a scale animation will.</p> 931 * 932 * @return true if this animation will change the transformation matrix 933 */ willChangeTransformationMatrix()934 public boolean willChangeTransformationMatrix() { 935 // assume we will change the matrix 936 return true; 937 } 938 939 /** 940 * <p>Indicates whether or not this animation will affect the bounds of the 941 * animated view. For instance, a fade animation will not affect the bounds 942 * whereas a 200% scale animation will.</p> 943 * 944 * @return true if this animation will change the view's bounds 945 */ willChangeBounds()946 public boolean willChangeBounds() { 947 // assume we will change the bounds 948 return true; 949 } 950 hasAnimationListener()951 private boolean hasAnimationListener() { 952 return mListener != null; 953 } 954 955 /** 956 * <p>Binds an animation listener to this animation. The animation listener 957 * is notified of animation events such as the end of the animation or the 958 * repetition of the animation.</p> 959 * 960 * @param listener the animation listener to be notified 961 */ setAnimationListener(AnimationListener listener)962 public void setAnimationListener(AnimationListener listener) { 963 mListener = listener; 964 } 965 966 /** 967 * Gurantees that this animation has an interpolator. Will use 968 * a AccelerateDecelerateInterpolator is nothing else was specified. 969 */ ensureInterpolator()970 protected void ensureInterpolator() { 971 if (mInterpolator == null) { 972 mInterpolator = new AccelerateDecelerateInterpolator(); 973 } 974 } 975 976 /** 977 * Compute a hint at how long the entire animation may last, in milliseconds. 978 * Animations can be written to cause themselves to run for a different 979 * duration than what is computed here, but generally this should be 980 * accurate. 981 */ computeDurationHint()982 public long computeDurationHint() { 983 return (getStartOffset() + getDuration()) * (getRepeatCount() + 1); 984 } 985 986 /** 987 * Gets the transformation to apply a specific point in time. Implementations of this method 988 * should always be kept in sync with getTransformation. 989 * 990 * @param normalizedTime time between 0 and 1 where 0 is the start of the animation and 1 the 991 * end. 992 * @param outTransformation A transformation object that is provided by the 993 * caller and will be filled in by the animation. 994 * @hide 995 */ getTransformationAt(float normalizedTime, Transformation outTransformation)996 public void getTransformationAt(float normalizedTime, Transformation outTransformation) { 997 final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime); 998 applyTransformation(interpolatedTime, outTransformation); 999 } 1000 1001 /** 1002 * Gets the transformation to apply at a specified point in time. Implementations of this 1003 * method should always replace the specified Transformation or document they are doing 1004 * otherwise. 1005 * 1006 * @param currentTime Where we are in the animation. This is wall clock time. 1007 * @param outTransformation A transformation object that is provided by the 1008 * caller and will be filled in by the animation. 1009 * @return True if the animation is still running 1010 */ getTransformation(long currentTime, Transformation outTransformation)1011 public boolean getTransformation(long currentTime, Transformation outTransformation) { 1012 if (mStartTime == -1) { 1013 mStartTime = currentTime; 1014 } 1015 1016 final long startOffset = getStartOffset(); 1017 final long duration = mDuration; 1018 float normalizedTime; 1019 if (duration != 0) { 1020 normalizedTime = ((float) (currentTime - (mStartTime + startOffset))) / 1021 (float) duration; 1022 } else { 1023 // time is a step-change with a zero duration 1024 normalizedTime = currentTime < mStartTime ? 0.0f : 1.0f; 1025 } 1026 1027 final boolean expired = normalizedTime >= 1.0f || isCanceled(); 1028 mMore = !expired; 1029 1030 if (!mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f); 1031 1032 if ((normalizedTime >= 0.0f || mFillBefore) && (normalizedTime <= 1.0f || mFillAfter)) { 1033 if (!mStarted) { 1034 fireAnimationStart(); 1035 mStarted = true; 1036 if (NoImagePreloadHolder.USE_CLOSEGUARD) { 1037 guard.open("cancel or detach or getTransformation"); 1038 } 1039 } 1040 1041 if (mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f); 1042 1043 if (mCycleFlip) { 1044 normalizedTime = 1.0f - normalizedTime; 1045 } 1046 1047 getTransformationAt(normalizedTime, outTransformation); 1048 } 1049 1050 if (expired) { 1051 if (mRepeatCount == mRepeated || isCanceled()) { 1052 if (!mEnded) { 1053 mEnded = true; 1054 guard.close(); 1055 fireAnimationEnd(); 1056 } 1057 } else { 1058 if (mRepeatCount > 0) { 1059 mRepeated++; 1060 } 1061 1062 if (mRepeatMode == REVERSE) { 1063 mCycleFlip = !mCycleFlip; 1064 } 1065 1066 mStartTime = -1; 1067 mMore = true; 1068 1069 fireAnimationRepeat(); 1070 } 1071 } 1072 1073 if (!mMore && mOneMoreTime) { 1074 mOneMoreTime = false; 1075 return true; 1076 } 1077 1078 return mMore; 1079 } 1080 isCanceled()1081 private boolean isCanceled() { 1082 return mStartTime == Long.MIN_VALUE; 1083 } 1084 fireAnimationStart()1085 private void fireAnimationStart() { 1086 if (hasAnimationListener()) { 1087 if (mListenerHandler == null) dispatchAnimationStart(); 1088 else mListenerHandler.postAtFrontOfQueue(mOnStart); 1089 } 1090 } 1091 fireAnimationRepeat()1092 private void fireAnimationRepeat() { 1093 if (hasAnimationListener()) { 1094 if (mListenerHandler == null) dispatchAnimationRepeat(); 1095 else mListenerHandler.postAtFrontOfQueue(mOnRepeat); 1096 } 1097 } 1098 fireAnimationEnd()1099 private void fireAnimationEnd() { 1100 if (hasAnimationListener()) { 1101 if (mListenerHandler == null) dispatchAnimationEnd(); 1102 else mListenerHandler.postAtFrontOfQueue(mOnEnd); 1103 } 1104 } 1105 dispatchAnimationStart()1106 void dispatchAnimationStart() { 1107 if (mListener != null) { 1108 mListener.onAnimationStart(this); 1109 } 1110 } 1111 dispatchAnimationRepeat()1112 void dispatchAnimationRepeat() { 1113 if (mListener != null) { 1114 mListener.onAnimationRepeat(this); 1115 } 1116 } 1117 dispatchAnimationEnd()1118 void dispatchAnimationEnd() { 1119 if (mListener != null) { 1120 mListener.onAnimationEnd(this); 1121 } 1122 } 1123 1124 /** 1125 * Gets the transformation to apply at a specified point in time. Implementations of this 1126 * method should always replace the specified Transformation or document they are doing 1127 * otherwise. 1128 * 1129 * @param currentTime Where we are in the animation. This is wall clock time. 1130 * @param outTransformation A transformation object that is provided by the 1131 * caller and will be filled in by the animation. 1132 * @param scale Scaling factor to apply to any inputs to the transform operation, such 1133 * pivot points being rotated or scaled around. 1134 * @return True if the animation is still running 1135 */ getTransformation(long currentTime, Transformation outTransformation, float scale)1136 public boolean getTransformation(long currentTime, Transformation outTransformation, 1137 float scale) { 1138 mScaleFactor = scale; 1139 return getTransformation(currentTime, outTransformation); 1140 } 1141 1142 /** 1143 * <p>Indicates whether this animation has started or not.</p> 1144 * 1145 * @return true if the animation has started, false otherwise 1146 */ hasStarted()1147 public boolean hasStarted() { 1148 return mStarted; 1149 } 1150 1151 /** 1152 * <p>Indicates whether this animation has ended or not.</p> 1153 * 1154 * @return true if the animation has ended, false otherwise 1155 */ hasEnded()1156 public boolean hasEnded() { 1157 return mEnded; 1158 } 1159 1160 /** 1161 * Helper for getTransformation. Subclasses should implement this to apply 1162 * their transforms given an interpolation value. Implementations of this 1163 * method should always replace the specified Transformation or document 1164 * they are doing otherwise. 1165 * 1166 * @param interpolatedTime The value of the normalized time (0.0 to 1.0) 1167 * after it has been run through the interpolation function. 1168 * @param t The Transformation object to fill in with the current 1169 * transforms. 1170 */ applyTransformation(float interpolatedTime, Transformation t)1171 protected void applyTransformation(float interpolatedTime, Transformation t) { 1172 } 1173 1174 /** 1175 * Convert the information in the description of a size to an actual 1176 * dimension 1177 * 1178 * @param type One of Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or 1179 * Animation.RELATIVE_TO_PARENT. 1180 * @param value The dimension associated with the type parameter 1181 * @param size The size of the object being animated 1182 * @param parentSize The size of the parent of the object being animated 1183 * @return The dimension to use for the animation 1184 */ resolveSize(int type, float value, int size, int parentSize)1185 protected float resolveSize(int type, float value, int size, int parentSize) { 1186 switch (type) { 1187 case ABSOLUTE: 1188 return value; 1189 case RELATIVE_TO_SELF: 1190 return size * value; 1191 case RELATIVE_TO_PARENT: 1192 return parentSize * value; 1193 default: 1194 return value; 1195 } 1196 } 1197 1198 /** 1199 * @param left 1200 * @param top 1201 * @param right 1202 * @param bottom 1203 * @param invalidate 1204 * @param transformation 1205 * 1206 * @hide 1207 */ 1208 @UnsupportedAppUsage getInvalidateRegion(int left, int top, int right, int bottom, RectF invalidate, Transformation transformation)1209 public void getInvalidateRegion(int left, int top, int right, int bottom, 1210 RectF invalidate, Transformation transformation) { 1211 1212 final RectF tempRegion = mRegion; 1213 final RectF previousRegion = mPreviousRegion; 1214 1215 invalidate.set(left, top, right, bottom); 1216 transformation.getMatrix().mapRect(invalidate); 1217 // Enlarge the invalidate region to account for rounding errors 1218 invalidate.inset(-1.0f, -1.0f); 1219 tempRegion.set(invalidate); 1220 invalidate.union(previousRegion); 1221 1222 previousRegion.set(tempRegion); 1223 1224 final Transformation tempTransformation = mTransformation; 1225 final Transformation previousTransformation = mPreviousTransformation; 1226 1227 tempTransformation.set(transformation); 1228 transformation.set(previousTransformation); 1229 previousTransformation.set(tempTransformation); 1230 } 1231 1232 /** 1233 * @param left 1234 * @param top 1235 * @param right 1236 * @param bottom 1237 * 1238 * @hide 1239 */ 1240 @UnsupportedAppUsage initializeInvalidateRegion(int left, int top, int right, int bottom)1241 public void initializeInvalidateRegion(int left, int top, int right, int bottom) { 1242 final RectF region = mPreviousRegion; 1243 region.set(left, top, right, bottom); 1244 // Enlarge the invalidate region to account for rounding errors 1245 region.inset(-1.0f, -1.0f); 1246 if (mFillBefore) { 1247 final Transformation previousTransformation = mPreviousTransformation; 1248 applyTransformation(mInterpolator.getInterpolation(0.0f), previousTransformation); 1249 } 1250 } 1251 finalize()1252 protected void finalize() throws Throwable { 1253 try { 1254 if (guard != null) { 1255 guard.warnIfOpen(); 1256 } 1257 } finally { 1258 super.finalize(); 1259 } 1260 } 1261 1262 /** 1263 * Return true if this animation changes the view's alpha property. 1264 * 1265 * @hide 1266 */ hasAlpha()1267 public boolean hasAlpha() { 1268 return false; 1269 } 1270 1271 /** 1272 * Utility class to parse a string description of a size. 1273 */ 1274 protected static class Description { 1275 /** 1276 * One of Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or 1277 * Animation.RELATIVE_TO_PARENT. 1278 */ 1279 public int type; 1280 1281 /** 1282 * The absolute or relative dimension for this Description. 1283 */ 1284 public float value; 1285 1286 /** 1287 * Size descriptions can appear in four forms: 1288 * <ol> 1289 * <li>An absolute size. This is represented by a number.</li> 1290 * <li>A size relative to the size of the object being animated. This 1291 * is represented by a number followed by "%".</li> 1292 * <li>A size relative to the size of the parent of object being 1293 * animated. This is represented by a number followed by "%p".</li> 1294 * <li>(Starting from API 32) A complex number.</li> 1295 * </ol> 1296 * @param value The typed value to parse 1297 * @return The parsed version of the description 1298 */ parseValue(TypedValue value, Context context)1299 static Description parseValue(TypedValue value, Context context) { 1300 Description d = new Description(); 1301 if (value == null) { 1302 d.type = ABSOLUTE; 1303 d.value = 0; 1304 } else { 1305 if (value.type == TypedValue.TYPE_FRACTION) { 1306 d.type = (value.data & TypedValue.COMPLEX_UNIT_MASK) == 1307 TypedValue.COMPLEX_UNIT_FRACTION_PARENT ? 1308 RELATIVE_TO_PARENT : RELATIVE_TO_SELF; 1309 d.value = TypedValue.complexToFloat(value.data); 1310 return d; 1311 } else if (value.type == TypedValue.TYPE_FLOAT) { 1312 d.type = ABSOLUTE; 1313 d.value = value.getFloat(); 1314 return d; 1315 } else if (value.type >= TypedValue.TYPE_FIRST_INT && 1316 value.type <= TypedValue.TYPE_LAST_INT) { 1317 d.type = ABSOLUTE; 1318 d.value = value.data; 1319 return d; 1320 } else if (value.type == TypedValue.TYPE_DIMENSION) { 1321 d.type = ABSOLUTE; 1322 d.value = TypedValue.complexToDimension(value.data, 1323 context.getResources().getDisplayMetrics()); 1324 return d; 1325 } 1326 } 1327 1328 d.type = ABSOLUTE; 1329 d.value = 0.0f; 1330 1331 return d; 1332 } 1333 } 1334 1335 /** 1336 * <p>An animation listener receives notifications from an animation. 1337 * Notifications indicate animation related events, such as the end or the 1338 * repetition of the animation.</p> 1339 */ 1340 public static interface AnimationListener { 1341 /** 1342 * <p>Notifies the start of the animation.</p> 1343 * 1344 * @param animation The started animation. 1345 */ 1346 void onAnimationStart(Animation animation); 1347 1348 /** 1349 * <p>Notifies the end of the animation. This callback is not invoked 1350 * for animations with repeat count set to INFINITE.</p> 1351 * 1352 * @param animation The animation which reached its end. 1353 */ 1354 void onAnimationEnd(Animation animation); 1355 1356 /** 1357 * <p>Notifies the repetition of the animation.</p> 1358 * 1359 * @param animation The animation which was repeated. 1360 */ 1361 void onAnimationRepeat(Animation animation); 1362 } 1363 } 1364