Animation.java revision 9266c558bf1d21ff647525ff99f7dadbca417309
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.util.AttributeSet; 22import android.util.TypedValue; 23 24/** 25 * Abstraction for an Animation that can be applied to Views, Surfaces, or 26 * other objects. See the {@link android.view.animation animation package 27 * description file}. 28 */ 29public abstract class Animation { 30 /** 31 * Repeat the animation indefinitely. 32 */ 33 public static final int INFINITE = -1; 34 35 /** 36 * When the animation reaches the end and the repeat count is INFINTE_REPEAT 37 * or a positive value, the animation restarts from the beginning. 38 */ 39 public static final int RESTART = 1; 40 41 /** 42 * When the animation reaches the end and the repeat count is INFINTE_REPEAT 43 * or a positive value, the animation plays backward (and then forward again). 44 */ 45 public static final int REVERSE = 2; 46 47 /** 48 * Can be used as the start time to indicate the start time should be the current 49 * time when {@link #getTransformation(long, Transformation)} is invoked for the 50 * first animation frame. This can is useful for short animations. 51 */ 52 public static final int START_ON_FIRST_FRAME = -1; 53 54 /** 55 * The specified dimension is an absolute number of pixels. 56 */ 57 public static final int ABSOLUTE = 0; 58 59 /** 60 * The specified dimension holds a float and should be multiplied by the 61 * height or width of the object being animated. 62 */ 63 public static final int RELATIVE_TO_SELF = 1; 64 65 /** 66 * The specified dimension holds a float and should be multiplied by the 67 * height or width of the parent of the object being animated. 68 */ 69 public static final int RELATIVE_TO_PARENT = 2; 70 71 /** 72 * Requests that the content being animated be kept in its current Z 73 * order. 74 */ 75 public static final int ZORDER_NORMAL = 0; 76 77 /** 78 * Requests that the content being animated be forced on top of all other 79 * content for the duration of the animation. 80 */ 81 public static final int ZORDER_TOP = 1; 82 83 /** 84 * Requests that the content being animated be forced under all other 85 * content for the duration of the animation. 86 */ 87 public static final int ZORDER_BOTTOM = -1; 88 89 /** 90 * Set by {@link #getTransformation(long, Transformation)} when the animation ends. 91 */ 92 boolean mEnded = false; 93 94 /** 95 * Set by {@link #getTransformation(long, Transformation)} when the animation starts. 96 */ 97 boolean mStarted = false; 98 99 /** 100 * Set by {@link #getTransformation(long, Transformation)} when the animation repeats 101 * in REVERSE mode. 102 */ 103 boolean mCycleFlip = false; 104 105 /** 106 * This value must be set to true by {@link #initialize(int, int, int, int)}. It 107 * indicates the animation was successfully initialized and can be played. 108 */ 109 boolean mInitialized = false; 110 111 /** 112 * Indicates whether the animation transformation should be applied before the 113 * animation starts. 114 */ 115 boolean mFillBefore = true; 116 117 /** 118 * Indicates whether the animation transformation should be applied after the 119 * animation ends. 120 */ 121 boolean mFillAfter = false; 122 123 /** 124 * Indicates whether fillAfter should be taken into account. 125 */ 126 boolean mFillEnabled = false; 127 128 /** 129 * The time in milliseconds at which the animation must start; 130 */ 131 long mStartTime = -1; 132 133 /** 134 * The delay in milliseconds after which the animation must start. When the 135 * start offset is > 0, the start time of the animation is startTime + startOffset. 136 */ 137 long mStartOffset; 138 139 /** 140 * The duration of one animation cycle in milliseconds. 141 */ 142 long mDuration; 143 144 /** 145 * The number of times the animation must repeat. By default, an animation repeats 146 * indefinitely. 147 */ 148 int mRepeatCount = 0; 149 150 /** 151 * Indicates how many times the animation was repeated. 152 */ 153 int mRepeated = 0; 154 155 /** 156 * The behavior of the animation when it repeats. The repeat mode is either 157 * {@link #RESTART} or {@link #REVERSE}. 158 * 159 */ 160 int mRepeatMode = RESTART; 161 162 /** 163 * The interpolator used by the animation to smooth the movement. 164 */ 165 Interpolator mInterpolator; 166 167 /** 168 * The animation listener to be notified when the animation starts, ends or repeats. 169 */ 170 AnimationListener mListener; 171 172 /** 173 * Desired Z order mode during animation. 174 */ 175 private int mZAdjustment; 176 177 // Indicates what was the last value returned by getTransformation() 178 private boolean mMore = true; 179 180 /** 181 * Creates a new animation with a duration of 0ms, the default interpolator, with 182 * fillBefore set to true and fillAfter set to false 183 */ 184 public Animation() { 185 ensureInterpolator(); 186 } 187 188 /** 189 * Creates a new animation whose parameters come from the specified context and 190 * attributes set. 191 * 192 * @param context the application environment 193 * @param attrs the set of attributes holding the animation parameters 194 */ 195 public Animation(Context context, AttributeSet attrs) { 196 TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Animation); 197 198 setDuration((long) a.getInt(com.android.internal.R.styleable.Animation_duration, 0)); 199 setStartOffset((long) a.getInt(com.android.internal.R.styleable.Animation_startOffset, 0)); 200 201 setFillEnabled(a.getBoolean(com.android.internal.R.styleable.Animation_fillEnabled, mFillEnabled)); 202 setFillBefore(a.getBoolean(com.android.internal.R.styleable.Animation_fillBefore, mFillBefore)); 203 setFillAfter(a.getBoolean(com.android.internal.R.styleable.Animation_fillAfter, mFillAfter)); 204 205 final int resID = a.getResourceId(com.android.internal.R.styleable.Animation_interpolator, 0); 206 if (resID > 0) { 207 setInterpolator(context, resID); 208 } 209 210 setRepeatCount(a.getInt(com.android.internal.R.styleable.Animation_repeatCount, mRepeatCount)); 211 setRepeatMode(a.getInt(com.android.internal.R.styleable.Animation_repeatMode, RESTART)); 212 213 setZAdjustment(a.getInt(com.android.internal.R.styleable.Animation_zAdjustment, ZORDER_NORMAL)); 214 215 ensureInterpolator(); 216 217 a.recycle(); 218 } 219 220 /** 221 * Reset the initialization state of this animation. 222 * 223 * @see #initialize(int, int, int, int) 224 */ 225 public void reset() { 226 mInitialized = false; 227 mCycleFlip = false; 228 mRepeated = 0; 229 mMore = true; 230 } 231 232 /** 233 * Whether or not the animation has been initialized. 234 * 235 * @return Has this animation been initialized. 236 * @see #initialize(int, int, int, int) 237 */ 238 public boolean isInitialized() { 239 return mInitialized; 240 } 241 242 /** 243 * Initialize this animation with the dimensions of the object being 244 * animated as well as the objects parents. (This is to support animation 245 * sizes being specifed relative to these dimensions.) 246 * 247 * <p>Objects that interpret a Animations should call this method when 248 * the sizes of the object being animated and its parent are known, and 249 * before calling {@link #getTransformation}. 250 * 251 * 252 * @param width Width of the object being animated 253 * @param height Height of the object being animated 254 * @param parentWidth Width of the animated object's parent 255 * @param parentHeight Height of the animated object's parent 256 */ 257 public void initialize(int width, int height, int parentWidth, int parentHeight) { 258 mInitialized = true; 259 mCycleFlip = false; 260 mRepeated = 0; 261 mMore = true; 262 } 263 264 /** 265 * Sets the acceleration curve for this animation. The interpolator is loaded as 266 * a resource from the specified context. 267 * 268 * @param context The application environment 269 * @param resID The resource identifier of the interpolator to load 270 * @attr ref android.R.styleable#Animation_interpolator 271 */ 272 public void setInterpolator(Context context, int resID) { 273 setInterpolator(AnimationUtils.loadInterpolator(context, resID)); 274 } 275 276 /** 277 * Sets the acceleration curve for this animation. Defaults to a linear 278 * interpolation. 279 * 280 * @param i The interpolator which defines the acceleration curve 281 * @attr ref android.R.styleable#Animation_interpolator 282 */ 283 public void setInterpolator(Interpolator i) { 284 mInterpolator = i; 285 } 286 287 /** 288 * When this animation should start relative to the start time. This is most 289 * useful when composing complex animations using an {@link AnimationSet } 290 * where some of the animations components start at different times. 291 * 292 * @param startOffset When this Animation should start, in milliseconds from 293 * the start time of the root AnimationSet. 294 * @attr ref android.R.styleable#Animation_startOffset 295 */ 296 public void setStartOffset(long startOffset) { 297 mStartOffset = startOffset; 298 } 299 300 /** 301 * How long this animation should last. The duration cannot be negative. 302 * 303 * @param durationMillis Duration in milliseconds 304 * 305 * @throw java.lang.IllegalArgumentException if the duration is < 0 306 * 307 * @attr ref android.R.styleable#Animation_duration 308 */ 309 public void setDuration(long durationMillis) { 310 if (durationMillis < 0) { 311 throw new IllegalArgumentException("Animation duration cannot be negative"); 312 } 313 mDuration = durationMillis; 314 } 315 316 /** 317 * Ensure that the duration that this animation will run is not longer 318 * than <var>durationMillis</var>. In addition to adjusting the duration 319 * itself, this ensures that the repeat count also will not make it run 320 * longer than the given time. 321 * 322 * @param durationMillis The maximum duration the animation is allowed 323 * to run. 324 */ 325 public void restrictDuration(long durationMillis) { 326 if (mStartOffset > durationMillis) { 327 mStartOffset = durationMillis; 328 mDuration = 0; 329 mRepeatCount = 0; 330 return; 331 } 332 333 long dur = mDuration + mStartOffset; 334 if (dur > durationMillis) { 335 mDuration = dur = durationMillis-mStartOffset; 336 } 337 if (mRepeatCount < 0 || mRepeatCount > durationMillis 338 || (dur*mRepeatCount) > durationMillis) { 339 mRepeatCount = (int)(durationMillis/dur); 340 } 341 } 342 343 /** 344 * How much to scale the duration by. 345 * 346 * @param scale The amount to scale the duration. 347 */ 348 public void scaleCurrentDuration(float scale) { 349 mDuration = (long) (mDuration * scale); 350 } 351 352 /** 353 * When this animation should start. When the start time is set to 354 * {@link #START_ON_FIRST_FRAME}, the animation will start the first time 355 * {@link #getTransformation(long, Transformation)} is invoked. The time passed 356 * to this method should be obtained by calling 357 * {@link AnimationUtils#currentAnimationTimeMillis()} instead of 358 * {@link System#currentTimeMillis()}. 359 * 360 * @param startTimeMillis the start time in milliseconds 361 */ 362 public void setStartTime(long startTimeMillis) { 363 mStartTime = startTimeMillis; 364 mStarted = mEnded = false; 365 mCycleFlip = false; 366 mRepeated = 0; 367 mMore = true; 368 } 369 370 /** 371 * Convenience method to start the animation the first time 372 * {@link #getTransformation(long, Transformation)} is invoked. 373 */ 374 public void start() { 375 setStartTime(-1); 376 } 377 378 /** 379 * Convenience method to start the animation at the current time in 380 * milliseconds. 381 */ 382 public void startNow() { 383 setStartTime(AnimationUtils.currentAnimationTimeMillis()); 384 } 385 386 /** 387 * Defines what this animation should do when it reaches the end. This 388 * setting is applied only when the repeat count is either greater than 389 * 0 or {@link #INFINITE}. Defaults to {@link #RESTART}. 390 * 391 * @param repeatMode {@link #RESTART} or {@link #REVERSE} 392 * @attr ref android.R.styleable#Animation_repeatMode 393 */ 394 public void setRepeatMode(int repeatMode) { 395 mRepeatMode = repeatMode; 396 } 397 398 /** 399 * Sets how many times the animation should be repeated. If the repeat 400 * count is 0, the animation is never repeated. If the repeat count is 401 * greater than 0 or {@link #INFINITE}, the repeat mode will be taken 402 * into account. The repeat count if 0 by default. 403 * 404 * @param repeatCount the number of times the animation should be repeated 405 * @attr ref android.R.styleable#Animation_repeatCount 406 */ 407 public void setRepeatCount(int repeatCount) { 408 if (repeatCount < 0) { 409 repeatCount = INFINITE; 410 } 411 mRepeatCount = repeatCount; 412 } 413 414 /** 415 * If fillEnabled is true, this animation will apply fillBefore and fillAfter. 416 * 417 * @return true if the animation will take fillBefore and fillAfter into account 418 * @attr ref android.R.styleable#Animation_fillEnabled 419 */ 420 public boolean isFillEnabled() { 421 return mFillEnabled; 422 } 423 424 /** 425 * If fillEnabled is true, the animation will apply the value of fillBefore and 426 * fillAfter. Otherwise, fillBefore and fillAfter are ignored and the animation 427 * transformation is always applied. 428 * 429 * @param fillEnabled true if the animation should take fillBefore and fillAfter into account 430 * @attr ref android.R.styleable#Animation_fillEnabled 431 * 432 * @see #setFillBefore(boolean) 433 * @see #setFillAfter(boolean) 434 */ 435 public void setFillEnabled(boolean fillEnabled) { 436 mFillEnabled = fillEnabled; 437 } 438 439 /** 440 * If fillBefore is true, this animation will apply its transformation 441 * before the start time of the animation. Defaults to true if not set. 442 * Note that this applies when using an {@link 443 * android.view.animation.AnimationSet AnimationSet} to chain 444 * animations. The transformation is not applied before the AnimationSet 445 * itself starts. 446 * 447 * @param fillBefore true if the animation should apply its transformation before it starts 448 * @attr ref android.R.styleable#Animation_fillBefore 449 * 450 * @see #setFillEnabled(boolean) 451 */ 452 public void setFillBefore(boolean fillBefore) { 453 mFillBefore = fillBefore; 454 } 455 456 /** 457 * If fillAfter is true, the transformation that this animation performed 458 * will persist when it is finished. Defaults to false if not set. 459 * Note that this applies when using an {@link 460 * android.view.animation.AnimationSet AnimationSet} to chain 461 * animations. The transformation is not applied before the AnimationSet 462 * itself starts. 463 * 464 * @param fillAfter true if the animation should apply its transformation after it ends 465 * @attr ref android.R.styleable#Animation_fillAfter 466 * 467 * @see #setFillEnabled(boolean) 468 */ 469 public void setFillAfter(boolean fillAfter) { 470 mFillAfter = fillAfter; 471 } 472 473 /** 474 * Set the Z ordering mode to use while running the animation. 475 * 476 * @param zAdjustment The desired mode, one of {@link #ZORDER_NORMAL}, 477 * {@link #ZORDER_TOP}, or {@link #ZORDER_BOTTOM}. 478 * @attr ref android.R.styleable#Animation_zAdjustment 479 */ 480 public void setZAdjustment(int zAdjustment) { 481 mZAdjustment = zAdjustment; 482 } 483 484 /** 485 * Gets the acceleration curve type for this animation. 486 * 487 * @return the {@link Interpolator} associated to this animation 488 * @attr ref android.R.styleable#Animation_interpolator 489 */ 490 public Interpolator getInterpolator() { 491 return mInterpolator; 492 } 493 494 /** 495 * When this animation should start. If the animation has not startet yet, 496 * this method might return {@link #START_ON_FIRST_FRAME}. 497 * 498 * @return the time in milliseconds when the animation should start or 499 * {@link #START_ON_FIRST_FRAME} 500 */ 501 public long getStartTime() { 502 return mStartTime; 503 } 504 505 /** 506 * How long this animation should last 507 * 508 * @return the duration in milliseconds of the animation 509 * @attr ref android.R.styleable#Animation_duration 510 */ 511 public long getDuration() { 512 return mDuration; 513 } 514 515 /** 516 * When this animation should start, relative to StartTime 517 * 518 * @return the start offset in milliseconds 519 * @attr ref android.R.styleable#Animation_startOffset 520 */ 521 public long getStartOffset() { 522 return mStartOffset; 523 } 524 525 /** 526 * Defines what this animation should do when it reaches the end. 527 * 528 * @return either one of {@link #REVERSE} or {@link #RESTART} 529 * @attr ref android.R.styleable#Animation_repeatMode 530 */ 531 public int getRepeatMode() { 532 return mRepeatMode; 533 } 534 535 /** 536 * Defines how many times the animation should repeat. The default value 537 * is 0. 538 * 539 * @return the number of times the animation should repeat, or {@link #INFINITE} 540 * @attr ref android.R.styleable#Animation_repeatCount 541 */ 542 public int getRepeatCount() { 543 return mRepeatCount; 544 } 545 546 /** 547 * If fillBefore is true, this animation will apply its transformation 548 * before the start time of the animation. 549 * 550 * @return true if the animation applies its transformation before it starts 551 * @attr ref android.R.styleable#Animation_fillBefore 552 */ 553 public boolean getFillBefore() { 554 return mFillBefore; 555 } 556 557 /** 558 * If fillAfter is true, this animation will apply its transformation 559 * after the end time of the animation. 560 * 561 * @return true if the animation applies its transformation after it ends 562 * @attr ref android.R.styleable#Animation_fillAfter 563 */ 564 public boolean getFillAfter() { 565 return mFillAfter; 566 } 567 568 /** 569 * Returns the Z ordering mode to use while running the animation as 570 * previously set by {@link #setZAdjustment}. 571 * 572 * @return Returns one of {@link #ZORDER_NORMAL}, 573 * {@link #ZORDER_TOP}, or {@link #ZORDER_BOTTOM}. 574 * @attr ref android.R.styleable#Animation_zAdjustment 575 */ 576 public int getZAdjustment() { 577 return mZAdjustment; 578 } 579 580 /** 581 * <p>Indicates whether or not this animation will affect the transformation 582 * matrix. For instance, a fade animation will not affect the matrix whereas 583 * a scale animation will.</p> 584 * 585 * @return true if this animation will change the transformation matrix 586 */ 587 public boolean willChangeTransformationMatrix() { 588 // assume we will change the matrix 589 return true; 590 } 591 592 /** 593 * <p>Indicates whether or not this animation will affect the bounds of the 594 * animated view. For instance, a fade animation will not affect the bounds 595 * whereas a 200% scale animation will.</p> 596 * 597 * @return true if this animation will change the view's bounds 598 */ 599 public boolean willChangeBounds() { 600 // assume we will change the bounds 601 return true; 602 } 603 604 /** 605 * <p>Binds an animation listener to this animation. The animation listener 606 * is notified of animation events such as the end of the animation or the 607 * repetition of the animation.</p> 608 * 609 * @param listener the animation listener to be notified 610 */ 611 public void setAnimationListener(AnimationListener listener) { 612 mListener = listener; 613 } 614 615 /** 616 * Gurantees that this animation has an interpolator. Will use 617 * a AccelerateDecelerateInterpolator is nothing else was specified. 618 */ 619 protected void ensureInterpolator() { 620 if (mInterpolator == null) { 621 mInterpolator = new AccelerateDecelerateInterpolator(); 622 } 623 } 624 625 /** 626 * Compute a hint at how long the entire animation may last, in milliseconds. 627 * Animations can be written to cause themselves to run for a different 628 * duration than what is computed here, but generally this should be 629 * accurate. 630 */ 631 public long computeDurationHint() { 632 return (getStartOffset() + getDuration()) * (getRepeatCount() + 1); 633 } 634 635 /** 636 * Gets the transformation to apply at a specified point in time. Implementations of this 637 * method should always replace the specified Transformation or document they are doing 638 * otherwise. 639 * 640 * @param currentTime Where we are in the animation. This is wall clock time. 641 * @param outTransformation A tranformation object that is provided by the 642 * caller and will be filled in by the animation. 643 * @return True if the animation is still running 644 */ 645 public boolean getTransformation(long currentTime, Transformation outTransformation) { 646 if (mStartTime == -1) { 647 mStartTime = currentTime; 648 } 649 650 final long startOffset = getStartOffset(); 651 final long duration = mDuration; 652 float normalizedTime; 653 if (duration != 0) { 654 normalizedTime = ((float) (currentTime - (mStartTime + startOffset))) / 655 (float) duration; 656 } else { 657 // time is a step-change with a zero duration 658 normalizedTime = currentTime < mStartTime ? 0.0f : 1.0f; 659 } 660 661 final boolean expired = normalizedTime >= 1.0f; 662 mMore = !expired; 663 664 if (!mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f); 665 666 if ((normalizedTime >= 0.0f || mFillBefore) && (normalizedTime <= 1.0f || mFillAfter)) { 667 if (!mStarted) { 668 if (mListener != null) { 669 mListener.onAnimationStart(this); 670 } 671 mStarted = true; 672 } 673 674 if (mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f); 675 676 if (mCycleFlip) { 677 normalizedTime = 1.0f - normalizedTime; 678 } 679 680 final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime); 681 applyTransformation(interpolatedTime, outTransformation); 682 } 683 684 if (expired) { 685 if (mRepeatCount == mRepeated) { 686 if (!mEnded) { 687 if (mListener != null) { 688 mListener.onAnimationEnd(this); 689 } 690 mEnded = true; 691 } 692 } else { 693 if (mRepeatCount > 0) { 694 mRepeated++; 695 } 696 697 if (mRepeatMode == REVERSE) { 698 mCycleFlip = !mCycleFlip; 699 } 700 701 mStartTime = -1; 702 mMore = true; 703 704 if (mListener != null) { 705 mListener.onAnimationRepeat(this); 706 } 707 } 708 } 709 710 return mMore; 711 } 712 713 /** 714 * <p>Indicates whether this animation has started or not.</p> 715 * 716 * @return true if the animation has started, false otherwise 717 */ 718 public boolean hasStarted() { 719 return mStarted; 720 } 721 722 /** 723 * <p>Indicates whether this animation has ended or not.</p> 724 * 725 * @return true if the animation has ended, false otherwise 726 */ 727 public boolean hasEnded() { 728 return mEnded; 729 } 730 731 /** 732 * Helper for getTransformation. Subclasses should implement this to apply 733 * their transforms given an interpolation value. Implementations of this 734 * method should always replace the specified Transformation or document 735 * they are doing otherwise. 736 * 737 * @param interpolatedTime The value of the normalized time (0.0 to 1.0) 738 * after it has been run through the interpolation function. 739 * @param t The Transofrmation object to fill in with the current 740 * transforms. 741 */ 742 protected void applyTransformation(float interpolatedTime, Transformation t) { 743 } 744 745 /** 746 * Convert the information in the description of a size to an actual 747 * dimension 748 * 749 * @param type One of Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or 750 * Animation.RELATIVE_TO_PARENT. 751 * @param value The dimension associated with the type parameter 752 * @param size The size of the object being animated 753 * @param parentSize The size of the parent of the object being animated 754 * @return The dimension to use for the animation 755 */ 756 protected float resolveSize(int type, float value, int size, int parentSize) { 757 switch (type) { 758 case ABSOLUTE: 759 return value; 760 case RELATIVE_TO_SELF: 761 return size * value; 762 case RELATIVE_TO_PARENT: 763 return parentSize * value; 764 default: 765 return value; 766 } 767 } 768 769 /** 770 * Utility class to parse a string description of a size. 771 */ 772 protected static class Description { 773 /** 774 * One of Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or 775 * Animation.RELATIVE_TO_PARENT. 776 */ 777 public int type; 778 779 /** 780 * The absolute or relative dimension for this Description. 781 */ 782 public float value; 783 784 /** 785 * Size descriptions can appear inthree forms: 786 * <ol> 787 * <li>An absolute size. This is represented by a number.</li> 788 * <li>A size relative to the size of the object being animated. This 789 * is represented by a number followed by "%".</li> * 790 * <li>A size relative to the size of the parent of object being 791 * animated. This is represented by a number followed by "%p".</li> 792 * </ol> 793 * @param value The typed value to parse 794 * @return The parsed version of the description 795 */ 796 static Description parseValue(TypedValue value) { 797 Description d = new Description(); 798 if (value == null) { 799 d.type = ABSOLUTE; 800 d.value = 0; 801 } else { 802 if (value.type == TypedValue.TYPE_FRACTION) { 803 d.type = (value.data & TypedValue.COMPLEX_UNIT_MASK) == 804 TypedValue.COMPLEX_UNIT_FRACTION_PARENT ? 805 RELATIVE_TO_PARENT : RELATIVE_TO_SELF; 806 d.value = TypedValue.complexToFloat(value.data); 807 return d; 808 } else if (value.type == TypedValue.TYPE_FLOAT) { 809 d.type = ABSOLUTE; 810 d.value = value.getFloat(); 811 return d; 812 } else if (value.type >= TypedValue.TYPE_FIRST_INT && 813 value.type <= TypedValue.TYPE_LAST_INT) { 814 d.type = ABSOLUTE; 815 d.value = value.data; 816 return d; 817 } 818 } 819 820 d.type = ABSOLUTE; 821 d.value = 0.0f; 822 823 return d; 824 } 825 } 826 827 /** 828 * <p>An animation listener receives notifications from an animation. 829 * Notifications indicate animation related events, such as the end or the 830 * repetition of the animation.</p> 831 */ 832 public static interface AnimationListener { 833 /** 834 * <p>Notifies the start of the animation.</p> 835 * 836 * @param animation The started animation. 837 */ 838 void onAnimationStart(Animation animation); 839 840 /** 841 * <p>Notifies the end of the animation. This callback is not invoked 842 * for animations with repeat count set to INFINITE.</p> 843 * 844 * @param animation The animation which reached its end. 845 */ 846 void onAnimationEnd(Animation animation); 847 848 /** 849 * <p>Notifies the repetition of the animation.</p> 850 * 851 * @param animation The animation which was repeated. 852 */ 853 void onAnimationRepeat(Animation animation); 854 } 855} 856