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