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