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