1 /* 2 * Copyright (C) 2010 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.animation; 18 19 import android.content.res.ConstantState; 20 21 import java.util.ArrayList; 22 23 /** 24 * This is the superclass for classes which provide basic support for animations which can be 25 * started, ended, and have <code>AnimatorListeners</code> added to them. 26 */ 27 public abstract class Animator implements Cloneable { 28 29 /** 30 * The set of listeners to be sent events through the life of an animation. 31 */ 32 ArrayList<AnimatorListener> mListeners = null; 33 34 /** 35 * The set of listeners to be sent pause/resume events through the life 36 * of an animation. 37 */ 38 ArrayList<AnimatorPauseListener> mPauseListeners = null; 39 40 /** 41 * Whether this animator is currently in a paused state. 42 */ 43 boolean mPaused = false; 44 45 /** 46 * A set of flags which identify the type of configuration changes that can affect this 47 * Animator. Used by the Animator cache. 48 */ 49 int mChangingConfigurations = 0; 50 51 /** 52 * If this animator is inflated from a constant state, keep a reference to it so that 53 * ConstantState will not be garbage collected until this animator is collected 54 */ 55 private AnimatorConstantState mConstantState; 56 57 /** 58 * Starts this animation. If the animation has a nonzero startDelay, the animation will start 59 * running after that delay elapses. A non-delayed animation will have its initial 60 * value(s) set immediately, followed by calls to 61 * {@link AnimatorListener#onAnimationStart(Animator)} for any listeners of this animator. 62 * 63 * <p>The animation started by calling this method will be run on the thread that called 64 * this method. This thread should have a Looper on it (a runtime exception will be thrown if 65 * this is not the case). Also, if the animation will animate 66 * properties of objects in the view hierarchy, then the calling thread should be the UI 67 * thread for that view hierarchy.</p> 68 * 69 */ 70 public void start() { 71 } 72 73 /** 74 * Cancels the animation. Unlike {@link #end()}, <code>cancel()</code> causes the animation to 75 * stop in its tracks, sending an 76 * {@link android.animation.Animator.AnimatorListener#onAnimationCancel(Animator)} to 77 * its listeners, followed by an 78 * {@link android.animation.Animator.AnimatorListener#onAnimationEnd(Animator)} message. 79 * 80 * <p>This method must be called on the thread that is running the animation.</p> 81 */ 82 public void cancel() { 83 } 84 85 /** 86 * Ends the animation. This causes the animation to assign the end value of the property being 87 * animated, then calling the 88 * {@link android.animation.Animator.AnimatorListener#onAnimationEnd(Animator)} method on 89 * its listeners. 90 * 91 * <p>This method must be called on the thread that is running the animation.</p> 92 */ 93 public void end() { 94 } 95 96 /** 97 * Pauses a running animation. This method should only be called on the same thread on 98 * which the animation was started. If the animation has not yet been {@link 99 * #isStarted() started} or has since ended, then the call is ignored. Paused 100 * animations can be resumed by calling {@link #resume()}. 101 * 102 * @see #resume() 103 * @see #isPaused() 104 * @see AnimatorPauseListener 105 */ 106 public void pause() { 107 if (isStarted() && !mPaused) { 108 mPaused = true; 109 if (mPauseListeners != null) { 110 ArrayList<AnimatorPauseListener> tmpListeners = 111 (ArrayList<AnimatorPauseListener>) mPauseListeners.clone(); 112 int numListeners = tmpListeners.size(); 113 for (int i = 0; i < numListeners; ++i) { 114 tmpListeners.get(i).onAnimationPause(this); 115 } 116 } 117 } 118 } 119 120 /** 121 * Resumes a paused animation, causing the animator to pick up where it left off 122 * when it was paused. This method should only be called on the same thread on 123 * which the animation was started. Calls to resume() on an animator that is 124 * not currently paused will be ignored. 125 * 126 * @see #pause() 127 * @see #isPaused() 128 * @see AnimatorPauseListener 129 */ 130 public void resume() { 131 if (mPaused) { 132 mPaused = false; 133 if (mPauseListeners != null) { 134 ArrayList<AnimatorPauseListener> tmpListeners = 135 (ArrayList<AnimatorPauseListener>) mPauseListeners.clone(); 136 int numListeners = tmpListeners.size(); 137 for (int i = 0; i < numListeners; ++i) { 138 tmpListeners.get(i).onAnimationResume(this); 139 } 140 } 141 } 142 } 143 144 /** 145 * Returns whether this animator is currently in a paused state. 146 * 147 * @return True if the animator is currently paused, false otherwise. 148 * 149 * @see #pause() 150 * @see #resume() 151 */ 152 public boolean isPaused() { 153 return mPaused; 154 } 155 156 /** 157 * The amount of time, in milliseconds, to delay processing the animation 158 * after {@link #start()} is called. 159 * 160 * @return the number of milliseconds to delay running the animation 161 */ 162 public abstract long getStartDelay(); 163 164 /** 165 * The amount of time, in milliseconds, to delay processing the animation 166 * after {@link #start()} is called. 167 168 * @param startDelay The amount of the delay, in milliseconds 169 */ 170 public abstract void setStartDelay(long startDelay); 171 172 /** 173 * Sets the duration of the animation. 174 * 175 * @param duration The length of the animation, in milliseconds. 176 */ 177 public abstract Animator setDuration(long duration); 178 179 /** 180 * Gets the duration of the animation. 181 * 182 * @return The length of the animation, in milliseconds. 183 */ 184 public abstract long getDuration(); 185 186 /** 187 * The time interpolator used in calculating the elapsed fraction of the 188 * animation. The interpolator determines whether the animation runs with 189 * linear or non-linear motion, such as acceleration and deceleration. The 190 * default value is {@link android.view.animation.AccelerateDecelerateInterpolator}. 191 * 192 * @param value the interpolator to be used by this animation 193 */ 194 public abstract void setInterpolator(TimeInterpolator value); 195 196 /** 197 * Returns the timing interpolator that this animation uses. 198 * 199 * @return The timing interpolator for this animation. 200 */ 201 public TimeInterpolator getInterpolator() { 202 return null; 203 } 204 205 /** 206 * Returns whether this Animator is currently running (having been started and gone past any 207 * initial startDelay period and not yet ended). 208 * 209 * @return Whether the Animator is running. 210 */ 211 public abstract boolean isRunning(); 212 213 /** 214 * Returns whether this Animator has been started and not yet ended. For reusable 215 * Animators (which most Animators are, apart from the one-shot animator produced by 216 * {@link android.view.ViewAnimationUtils#createCircularReveal( 217 * android.view.View, int, int, float, float) createCircularReveal()}), 218 * this state is a superset of {@link #isRunning()}, because an Animator with a 219 * nonzero {@link #getStartDelay() startDelay} will return true for {@link #isStarted()} during 220 * the delay phase, whereas {@link #isRunning()} will return true only after the delay phase 221 * is complete. Non-reusable animators will always return true after they have been 222 * started, because they cannot return to a non-started state. 223 * 224 * @return Whether the Animator has been started and not yet ended. 225 */ 226 public boolean isStarted() { 227 // Default method returns value for isRunning(). Subclasses should override to return a 228 // real value. 229 return isRunning(); 230 } 231 232 /** 233 * Adds a listener to the set of listeners that are sent events through the life of an 234 * animation, such as start, repeat, and end. 235 * 236 * @param listener the listener to be added to the current set of listeners for this animation. 237 */ 238 public void addListener(AnimatorListener listener) { 239 if (mListeners == null) { 240 mListeners = new ArrayList<AnimatorListener>(); 241 } 242 mListeners.add(listener); 243 } 244 245 /** 246 * Removes a listener from the set listening to this animation. 247 * 248 * @param listener the listener to be removed from the current set of listeners for this 249 * animation. 250 */ 251 public void removeListener(AnimatorListener listener) { 252 if (mListeners == null) { 253 return; 254 } 255 mListeners.remove(listener); 256 if (mListeners.size() == 0) { 257 mListeners = null; 258 } 259 } 260 261 /** 262 * Gets the set of {@link android.animation.Animator.AnimatorListener} objects that are currently 263 * listening for events on this <code>Animator</code> object. 264 * 265 * @return ArrayList<AnimatorListener> The set of listeners. 266 */ 267 public ArrayList<AnimatorListener> getListeners() { 268 return mListeners; 269 } 270 271 /** 272 * Adds a pause listener to this animator. 273 * 274 * @param listener the listener to be added to the current set of pause listeners 275 * for this animation. 276 */ 277 public void addPauseListener(AnimatorPauseListener listener) { 278 if (mPauseListeners == null) { 279 mPauseListeners = new ArrayList<AnimatorPauseListener>(); 280 } 281 mPauseListeners.add(listener); 282 } 283 284 /** 285 * Removes a pause listener from the set listening to this animation. 286 * 287 * @param listener the listener to be removed from the current set of pause 288 * listeners for this animation. 289 */ 290 public void removePauseListener(AnimatorPauseListener listener) { 291 if (mPauseListeners == null) { 292 return; 293 } 294 mPauseListeners.remove(listener); 295 if (mPauseListeners.size() == 0) { 296 mPauseListeners = null; 297 } 298 } 299 300 /** 301 * Removes all {@link #addListener(android.animation.Animator.AnimatorListener) listeners} 302 * and {@link #addPauseListener(android.animation.Animator.AnimatorPauseListener) 303 * pauseListeners} from this object. 304 */ 305 public void removeAllListeners() { 306 if (mListeners != null) { 307 mListeners.clear(); 308 mListeners = null; 309 } 310 if (mPauseListeners != null) { 311 mPauseListeners.clear(); 312 mPauseListeners = null; 313 } 314 } 315 316 /** 317 * Return a mask of the configuration parameters for which this animator may change, requiring 318 * that it should be re-created from Resources. The default implementation returns whatever 319 * value was provided through setChangingConfigurations(int) or 0 by default. 320 * 321 * @return Returns a mask of the changing configuration parameters, as defined by 322 * {@link android.content.pm.ActivityInfo}. 323 * @see android.content.pm.ActivityInfo 324 * @hide 325 */ 326 public int getChangingConfigurations() { 327 return mChangingConfigurations; 328 } 329 330 /** 331 * Set a mask of the configuration parameters for which this animator may change, requiring 332 * that it be re-created from resource. 333 * 334 * @param configs A mask of the changing configuration parameters, as 335 * defined by {@link android.content.pm.ActivityInfo}. 336 * 337 * @see android.content.pm.ActivityInfo 338 * @hide 339 */ 340 public void setChangingConfigurations(int configs) { 341 mChangingConfigurations = configs; 342 } 343 344 /** 345 * Sets the changing configurations value to the union of the current changing configurations 346 * and the provided configs. 347 * This method is called while loading the animator. 348 * @hide 349 */ 350 public void appendChangingConfigurations(int configs) { 351 mChangingConfigurations |= configs; 352 } 353 354 /** 355 * Return a {@link android.content.res.ConstantState} instance that holds the shared state of 356 * this Animator. 357 * <p> 358 * This constant state is used to create new instances of this animator when needed, instead 359 * of re-loading it from resources. Default implementation creates a new 360 * {@link AnimatorConstantState}. You can override this method to provide your custom logic or 361 * return null if you don't want this animator to be cached. 362 * 363 * @return The ConfigurationBoundResourceCache.BaseConstantState associated to this Animator. 364 * @see android.content.res.ConstantState 365 * @see #clone() 366 * @hide 367 */ 368 public ConstantState<Animator> createConstantState() { 369 return new AnimatorConstantState(this); 370 } 371 372 @Override 373 public Animator clone() { 374 try { 375 final Animator anim = (Animator) super.clone(); 376 if (mListeners != null) { 377 anim.mListeners = new ArrayList<AnimatorListener>(mListeners); 378 } 379 if (mPauseListeners != null) { 380 anim.mPauseListeners = new ArrayList<AnimatorPauseListener>(mPauseListeners); 381 } 382 return anim; 383 } catch (CloneNotSupportedException e) { 384 throw new AssertionError(); 385 } 386 } 387 388 /** 389 * This method tells the object to use appropriate information to extract 390 * starting values for the animation. For example, a AnimatorSet object will pass 391 * this call to its child objects to tell them to set up the values. A 392 * ObjectAnimator object will use the information it has about its target object 393 * and PropertyValuesHolder objects to get the start values for its properties. 394 * A ValueAnimator object will ignore the request since it does not have enough 395 * information (such as a target object) to gather these values. 396 */ 397 public void setupStartValues() { 398 } 399 400 /** 401 * This method tells the object to use appropriate information to extract 402 * ending values for the animation. For example, a AnimatorSet object will pass 403 * this call to its child objects to tell them to set up the values. A 404 * ObjectAnimator object will use the information it has about its target object 405 * and PropertyValuesHolder objects to get the start values for its properties. 406 * A ValueAnimator object will ignore the request since it does not have enough 407 * information (such as a target object) to gather these values. 408 */ 409 public void setupEndValues() { 410 } 411 412 /** 413 * Sets the target object whose property will be animated by this animation. Not all subclasses 414 * operate on target objects (for example, {@link ValueAnimator}, but this method 415 * is on the superclass for the convenience of dealing generically with those subclasses 416 * that do handle targets. 417 * 418 * @param target The object being animated 419 */ 420 public void setTarget(Object target) { 421 } 422 423 // Hide reverse() and canReverse() for now since reverse() only work for simple 424 // cases, like we don't support sequential, neither startDelay. 425 // TODO: make reverse() works for all the Animators. 426 /** 427 * @hide 428 */ 429 public boolean canReverse() { 430 return false; 431 } 432 433 /** 434 * @hide 435 */ 436 public void reverse() { 437 throw new IllegalStateException("Reverse is not supported"); 438 } 439 440 /** 441 * <p>An animation listener receives notifications from an animation. 442 * Notifications indicate animation related events, such as the end or the 443 * repetition of the animation.</p> 444 */ 445 public static interface AnimatorListener { 446 /** 447 * <p>Notifies the start of the animation.</p> 448 * 449 * @param animation The started animation. 450 */ 451 void onAnimationStart(Animator animation); 452 453 /** 454 * <p>Notifies the end of the animation. This callback is not invoked 455 * for animations with repeat count set to INFINITE.</p> 456 * 457 * @param animation The animation which reached its end. 458 */ 459 void onAnimationEnd(Animator animation); 460 461 /** 462 * <p>Notifies the cancellation of the animation. This callback is not invoked 463 * for animations with repeat count set to INFINITE.</p> 464 * 465 * @param animation The animation which was canceled. 466 */ 467 void onAnimationCancel(Animator animation); 468 469 /** 470 * <p>Notifies the repetition of the animation.</p> 471 * 472 * @param animation The animation which was repeated. 473 */ 474 void onAnimationRepeat(Animator animation); 475 } 476 477 /** 478 * A pause listener receives notifications from an animation when the 479 * animation is {@link #pause() paused} or {@link #resume() resumed}. 480 * 481 * @see #addPauseListener(AnimatorPauseListener) 482 */ 483 public static interface AnimatorPauseListener { 484 /** 485 * <p>Notifies that the animation was paused.</p> 486 * 487 * @param animation The animaton being paused. 488 * @see #pause() 489 */ 490 void onAnimationPause(Animator animation); 491 492 /** 493 * <p>Notifies that the animation was resumed, after being 494 * previously paused.</p> 495 * 496 * @param animation The animation being resumed. 497 * @see #resume() 498 */ 499 void onAnimationResume(Animator animation); 500 } 501 502 /** 503 * <p>Whether or not the Animator is allowed to run asynchronously off of 504 * the UI thread. This is a hint that informs the Animator that it is 505 * OK to run the animation off-thread, however the Animator may decide 506 * that it must run the animation on the UI thread anyway. 507 * 508 * <p>Regardless of whether or not the animation runs asynchronously, all 509 * listener callbacks will be called on the UI thread.</p> 510 * 511 * <p>To be able to use this hint the following must be true:</p> 512 * <ol> 513 * <li>The animator is immutable while {@link #isStarted()} is true. Requests 514 * to change duration, delay, etc... may be ignored.</li> 515 * <li>Lifecycle callback events may be asynchronous. Events such as 516 * {@link Animator.AnimatorListener#onAnimationEnd(Animator)} or 517 * {@link Animator.AnimatorListener#onAnimationRepeat(Animator)} may end up delayed 518 * as they must be posted back to the UI thread, and any actions performed 519 * by those callbacks (such as starting new animations) will not happen 520 * in the same frame.</li> 521 * <li>State change requests ({@link #cancel()}, {@link #end()}, {@link #reverse()}, etc...) 522 * may be asynchronous. It is guaranteed that all state changes that are 523 * performed on the UI thread in the same frame will be applied as a single 524 * atomic update, however that frame may be the current frame, 525 * the next frame, or some future frame. This will also impact the observed 526 * state of the Animator. For example, {@link #isStarted()} may still return true 527 * after a call to {@link #end()}. Using the lifecycle callbacks is preferred over 528 * queries to {@link #isStarted()}, {@link #isRunning()}, and {@link #isPaused()} 529 * for this reason.</li> 530 * </ol> 531 * @hide 532 */ 533 public void setAllowRunningAsynchronously(boolean mayRunAsync) { 534 // It is up to subclasses to support this, if they can. 535 } 536 537 /** 538 * Creates a {@link ConstantState} which holds changing configurations information associated 539 * with the given Animator. 540 * <p> 541 * When {@link #newInstance()} is called, default implementation clones the Animator. 542 */ 543 private static class AnimatorConstantState extends ConstantState<Animator> { 544 545 final Animator mAnimator; 546 int mChangingConf; 547 548 public AnimatorConstantState(Animator animator) { 549 mAnimator = animator; 550 // ensure a reference back to here so that constante state is not gc'ed. 551 mAnimator.mConstantState = this; 552 mChangingConf = mAnimator.getChangingConfigurations(); 553 } 554 555 @Override 556 public int getChangingConfigurations() { 557 return mChangingConf; 558 } 559 560 @Override 561 public Animator newInstance() { 562 final Animator clone = mAnimator.clone(); 563 clone.mConstantState = this; 564 return clone; 565 } 566 } 567 } 568