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