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