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