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