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