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