PageRenderTime 31ms CodeModel.GetById 0ms RepoModel.GetById 1ms app.codeStats 0ms

/core/java/android/animation/ValueAnimator.java

https://bitbucket.org/iainh/projectzzz-platform-frameworks-base
Java | 1271 lines | 575 code | 99 blank | 597 comment | 154 complexity | 3ab31113c813f6ae3db01cca9f7451b0 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, CC0-1.0

Large files files are truncated, but you can click here to view the full file

  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. package android.animation;
  17. import android.os.Handler;
  18. import android.os.Looper;
  19. import android.os.Message;
  20. import android.os.SystemProperties;
  21. import android.util.AndroidRuntimeException;
  22. import android.view.Choreographer;
  23. import android.view.animation.AccelerateDecelerateInterpolator;
  24. import android.view.animation.AnimationUtils;
  25. import android.view.animation.LinearInterpolator;
  26. import java.util.ArrayList;
  27. import java.util.HashMap;
  28. /**
  29. * This class provides a simple timing engine for running animations
  30. * which calculate animated values and set them on target objects.
  31. *
  32. * <p>There is a single timing pulse that all animations use. It runs in a
  33. * custom handler to ensure that property changes happen on the UI thread.</p>
  34. *
  35. * <p>By default, ValueAnimator uses non-linear time interpolation, via the
  36. * {@link AccelerateDecelerateInterpolator} class, which accelerates into and decelerates
  37. * out of an animation. This behavior can be changed by calling
  38. * {@link ValueAnimator#setInterpolator(TimeInterpolator)}.</p>
  39. *
  40. * <div class="special reference">
  41. * <h3>Developer Guides</h3>
  42. * <p>For more information about animating with {@code ValueAnimator}, read the
  43. * <a href="{@docRoot}guide/topics/graphics/prop-animation.html#value-animator">Property
  44. * Animation</a> developer guide.</p>
  45. * </div>
  46. */
  47. public class ValueAnimator extends Animator {
  48. /**
  49. * Internal constants
  50. */
  51. private static float sDurationScale = 1.0f;
  52. /**
  53. * Values used with internal variable mPlayingState to indicate the current state of an
  54. * animation.
  55. */
  56. static final int STOPPED = 0; // Not yet playing
  57. static final int RUNNING = 1; // Playing normally
  58. static final int SEEKED = 2; // Seeked to some time value
  59. /**
  60. * Internal variables
  61. * NOTE: This object implements the clone() method, making a deep copy of any referenced
  62. * objects. As other non-trivial fields are added to this class, make sure to add logic
  63. * to clone() to make deep copies of them.
  64. */
  65. // The first time that the animation's animateFrame() method is called. This time is used to
  66. // determine elapsed time (and therefore the elapsed fraction) in subsequent calls
  67. // to animateFrame()
  68. long mStartTime;
  69. /**
  70. * Set when setCurrentPlayTime() is called. If negative, animation is not currently seeked
  71. * to a value.
  72. */
  73. long mSeekTime = -1;
  74. // The static sAnimationHandler processes the internal timing loop on which all animations
  75. // are based
  76. private static ThreadLocal<AnimationHandler> sAnimationHandler =
  77. new ThreadLocal<AnimationHandler>();
  78. // The time interpolator to be used if none is set on the animation
  79. private static final TimeInterpolator sDefaultInterpolator =
  80. new AccelerateDecelerateInterpolator();
  81. /**
  82. * Used to indicate whether the animation is currently playing in reverse. This causes the
  83. * elapsed fraction to be inverted to calculate the appropriate values.
  84. */
  85. private boolean mPlayingBackwards = false;
  86. /**
  87. * This variable tracks the current iteration that is playing. When mCurrentIteration exceeds the
  88. * repeatCount (if repeatCount!=INFINITE), the animation ends
  89. */
  90. private int mCurrentIteration = 0;
  91. /**
  92. * Tracks current elapsed/eased fraction, for querying in getAnimatedFraction().
  93. */
  94. private float mCurrentFraction = 0f;
  95. /**
  96. * Tracks whether a startDelay'd animation has begun playing through the startDelay.
  97. */
  98. private boolean mStartedDelay = false;
  99. /**
  100. * Tracks the time at which the animation began playing through its startDelay. This is
  101. * different from the mStartTime variable, which is used to track when the animation became
  102. * active (which is when the startDelay expired and the animation was added to the active
  103. * animations list).
  104. */
  105. private long mDelayStartTime;
  106. /**
  107. * Flag that represents the current state of the animation. Used to figure out when to start
  108. * an animation (if state == STOPPED). Also used to end an animation that
  109. * has been cancel()'d or end()'d since the last animation frame. Possible values are
  110. * STOPPED, RUNNING, SEEKED.
  111. */
  112. int mPlayingState = STOPPED;
  113. /**
  114. * Additional playing state to indicate whether an animator has been start()'d. There is
  115. * some lag between a call to start() and the first animation frame. We should still note
  116. * that the animation has been started, even if it's first animation frame has not yet
  117. * happened, and reflect that state in isRunning().
  118. * Note that delayed animations are different: they are not started until their first
  119. * animation frame, which occurs after their delay elapses.
  120. */
  121. private boolean mRunning = false;
  122. /**
  123. * Additional playing state to indicate whether an animator has been start()'d, whether or
  124. * not there is a nonzero startDelay.
  125. */
  126. private boolean mStarted = false;
  127. /**
  128. * Tracks whether we've notified listeners of the onAnimationSTart() event. This can be
  129. * complex to keep track of since we notify listeners at different times depending on
  130. * startDelay and whether start() was called before end().
  131. */
  132. private boolean mStartListenersCalled = false;
  133. /**
  134. * Flag that denotes whether the animation is set up and ready to go. Used to
  135. * set up animation that has not yet been started.
  136. */
  137. boolean mInitialized = false;
  138. //
  139. // Backing variables
  140. //
  141. // How long the animation should last in ms
  142. private long mDuration = (long)(300 * sDurationScale);
  143. private long mUnscaledDuration = 300;
  144. // The amount of time in ms to delay starting the animation after start() is called
  145. private long mStartDelay = 0;
  146. private long mUnscaledStartDelay = 0;
  147. // The number of times the animation will repeat. The default is 0, which means the animation
  148. // will play only once
  149. private int mRepeatCount = 0;
  150. /**
  151. * The type of repetition that will occur when repeatMode is nonzero. RESTART means the
  152. * animation will start from the beginning on every new cycle. REVERSE means the animation
  153. * will reverse directions on each iteration.
  154. */
  155. private int mRepeatMode = RESTART;
  156. /**
  157. * The time interpolator to be used. The elapsed fraction of the animation will be passed
  158. * through this interpolator to calculate the interpolated fraction, which is then used to
  159. * calculate the animated values.
  160. */
  161. private TimeInterpolator mInterpolator = sDefaultInterpolator;
  162. /**
  163. * The set of listeners to be sent events through the life of an animation.
  164. */
  165. private ArrayList<AnimatorUpdateListener> mUpdateListeners = null;
  166. /**
  167. * The property/value sets being animated.
  168. */
  169. PropertyValuesHolder[] mValues;
  170. /**
  171. * A hashmap of the PropertyValuesHolder objects. This map is used to lookup animated values
  172. * by property name during calls to getAnimatedValue(String).
  173. */
  174. HashMap<String, PropertyValuesHolder> mValuesMap;
  175. /**
  176. * Public constants
  177. */
  178. /**
  179. * When the animation reaches the end and <code>repeatCount</code> is INFINITE
  180. * or a positive value, the animation restarts from the beginning.
  181. */
  182. public static final int RESTART = 1;
  183. /**
  184. * When the animation reaches the end and <code>repeatCount</code> is INFINITE
  185. * or a positive value, the animation reverses direction on every iteration.
  186. */
  187. public static final int REVERSE = 2;
  188. /**
  189. * This value used used with the {@link #setRepeatCount(int)} property to repeat
  190. * the animation indefinitely.
  191. */
  192. public static final int INFINITE = -1;
  193. /**
  194. * @hide
  195. */
  196. public static void setDurationScale(float durationScale) {
  197. sDurationScale = durationScale;
  198. }
  199. /**
  200. * Creates a new ValueAnimator object. This default constructor is primarily for
  201. * use internally; the factory methods which take parameters are more generally
  202. * useful.
  203. */
  204. public ValueAnimator() {
  205. }
  206. /**
  207. * Constructs and returns a ValueAnimator that animates between int values. A single
  208. * value implies that that value is the one being animated to. However, this is not typically
  209. * useful in a ValueAnimator object because there is no way for the object to determine the
  210. * starting value for the animation (unlike ObjectAnimator, which can derive that value
  211. * from the target object and property being animated). Therefore, there should typically
  212. * be two or more values.
  213. *
  214. * @param values A set of values that the animation will animate between over time.
  215. * @return A ValueAnimator object that is set up to animate between the given values.
  216. */
  217. public static ValueAnimator ofInt(int... values) {
  218. ValueAnimator anim = new ValueAnimator();
  219. anim.setIntValues(values);
  220. return anim;
  221. }
  222. /**
  223. * Constructs and returns a ValueAnimator that animates between float values. A single
  224. * value implies that that value is the one being animated to. However, this is not typically
  225. * useful in a ValueAnimator object because there is no way for the object to determine the
  226. * starting value for the animation (unlike ObjectAnimator, which can derive that value
  227. * from the target object and property being animated). Therefore, there should typically
  228. * be two or more values.
  229. *
  230. * @param values A set of values that the animation will animate between over time.
  231. * @return A ValueAnimator object that is set up to animate between the given values.
  232. */
  233. public static ValueAnimator ofFloat(float... values) {
  234. ValueAnimator anim = new ValueAnimator();
  235. anim.setFloatValues(values);
  236. return anim;
  237. }
  238. /**
  239. * Constructs and returns a ValueAnimator that animates between the values
  240. * specified in the PropertyValuesHolder objects.
  241. *
  242. * @param values A set of PropertyValuesHolder objects whose values will be animated
  243. * between over time.
  244. * @return A ValueAnimator object that is set up to animate between the given values.
  245. */
  246. public static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values) {
  247. ValueAnimator anim = new ValueAnimator();
  248. anim.setValues(values);
  249. return anim;
  250. }
  251. /**
  252. * Constructs and returns a ValueAnimator that animates between Object values. A single
  253. * value implies that that value is the one being animated to. However, this is not typically
  254. * useful in a ValueAnimator object because there is no way for the object to determine the
  255. * starting value for the animation (unlike ObjectAnimator, which can derive that value
  256. * from the target object and property being animated). Therefore, there should typically
  257. * be two or more values.
  258. *
  259. * <p>Since ValueAnimator does not know how to animate between arbitrary Objects, this
  260. * factory method also takes a TypeEvaluator object that the ValueAnimator will use
  261. * to perform that interpolation.
  262. *
  263. * @param evaluator A TypeEvaluator that will be called on each animation frame to
  264. * provide the ncessry interpolation between the Object values to derive the animated
  265. * value.
  266. * @param values A set of values that the animation will animate between over time.
  267. * @return A ValueAnimator object that is set up to animate between the given values.
  268. */
  269. public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values) {
  270. ValueAnimator anim = new ValueAnimator();
  271. anim.setObjectValues(values);
  272. anim.setEvaluator(evaluator);
  273. return anim;
  274. }
  275. /**
  276. * Sets int values that will be animated between. A single
  277. * value implies that that value is the one being animated to. However, this is not typically
  278. * useful in a ValueAnimator object because there is no way for the object to determine the
  279. * starting value for the animation (unlike ObjectAnimator, which can derive that value
  280. * from the target object and property being animated). Therefore, there should typically
  281. * be two or more values.
  282. *
  283. * <p>If there are already multiple sets of values defined for this ValueAnimator via more
  284. * than one PropertyValuesHolder object, this method will set the values for the first
  285. * of those objects.</p>
  286. *
  287. * @param values A set of values that the animation will animate between over time.
  288. */
  289. public void setIntValues(int... values) {
  290. if (values == null || values.length == 0) {
  291. return;
  292. }
  293. if (mValues == null || mValues.length == 0) {
  294. setValues(new PropertyValuesHolder[]{PropertyValuesHolder.ofInt("", values)});
  295. } else {
  296. PropertyValuesHolder valuesHolder = mValues[0];
  297. valuesHolder.setIntValues(values);
  298. }
  299. // New property/values/target should cause re-initialization prior to starting
  300. mInitialized = false;
  301. }
  302. /**
  303. * Sets float values that will be animated between. A single
  304. * value implies that that value is the one being animated to. However, this is not typically
  305. * useful in a ValueAnimator object because there is no way for the object to determine the
  306. * starting value for the animation (unlike ObjectAnimator, which can derive that value
  307. * from the target object and property being animated). Therefore, there should typically
  308. * be two or more values.
  309. *
  310. * <p>If there are already multiple sets of values defined for this ValueAnimator via more
  311. * than one PropertyValuesHolder object, this method will set the values for the first
  312. * of those objects.</p>
  313. *
  314. * @param values A set of values that the animation will animate between over time.
  315. */
  316. public void setFloatValues(float... values) {
  317. if (values == null || values.length == 0) {
  318. return;
  319. }
  320. if (mValues == null || mValues.length == 0) {
  321. setValues(new PropertyValuesHolder[]{PropertyValuesHolder.ofFloat("", values)});
  322. } else {
  323. PropertyValuesHolder valuesHolder = mValues[0];
  324. valuesHolder.setFloatValues(values);
  325. }
  326. // New property/values/target should cause re-initialization prior to starting
  327. mInitialized = false;
  328. }
  329. /**
  330. * Sets the values to animate between for this animation. A single
  331. * value implies that that value is the one being animated to. However, this is not typically
  332. * useful in a ValueAnimator object because there is no way for the object to determine the
  333. * starting value for the animation (unlike ObjectAnimator, which can derive that value
  334. * from the target object and property being animated). Therefore, there should typically
  335. * be two or more values.
  336. *
  337. * <p>If there are already multiple sets of values defined for this ValueAnimator via more
  338. * than one PropertyValuesHolder object, this method will set the values for the first
  339. * of those objects.</p>
  340. *
  341. * <p>There should be a TypeEvaluator set on the ValueAnimator that knows how to interpolate
  342. * between these value objects. ValueAnimator only knows how to interpolate between the
  343. * primitive types specified in the other setValues() methods.</p>
  344. *
  345. * @param values The set of values to animate between.
  346. */
  347. public void setObjectValues(Object... values) {
  348. if (values == null || values.length == 0) {
  349. return;
  350. }
  351. if (mValues == null || mValues.length == 0) {
  352. setValues(new PropertyValuesHolder[]{PropertyValuesHolder.ofObject("",
  353. (TypeEvaluator)null, values)});
  354. } else {
  355. PropertyValuesHolder valuesHolder = mValues[0];
  356. valuesHolder.setObjectValues(values);
  357. }
  358. // New property/values/target should cause re-initialization prior to starting
  359. mInitialized = false;
  360. }
  361. /**
  362. * Sets the values, per property, being animated between. This function is called internally
  363. * by the constructors of ValueAnimator that take a list of values. But a ValueAnimator can
  364. * be constructed without values and this method can be called to set the values manually
  365. * instead.
  366. *
  367. * @param values The set of values, per property, being animated between.
  368. */
  369. public void setValues(PropertyValuesHolder... values) {
  370. int numValues = values.length;
  371. mValues = values;
  372. mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
  373. for (int i = 0; i < numValues; ++i) {
  374. PropertyValuesHolder valuesHolder = (PropertyValuesHolder) values[i];
  375. mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);
  376. }
  377. // New property/values/target should cause re-initialization prior to starting
  378. mInitialized = false;
  379. }
  380. /**
  381. * Returns the values that this ValueAnimator animates between. These values are stored in
  382. * PropertyValuesHolder objects, even if the ValueAnimator was created with a simple list
  383. * of value objects instead.
  384. *
  385. * @return PropertyValuesHolder[] An array of PropertyValuesHolder objects which hold the
  386. * values, per property, that define the animation.
  387. */
  388. public PropertyValuesHolder[] getValues() {
  389. return mValues;
  390. }
  391. /**
  392. * This function is called immediately before processing the first animation
  393. * frame of an animation. If there is a nonzero <code>startDelay</code>, the
  394. * function is called after that delay ends.
  395. * It takes care of the final initialization steps for the
  396. * animation.
  397. *
  398. * <p>Overrides of this method should call the superclass method to ensure
  399. * that internal mechanisms for the animation are set up correctly.</p>
  400. */
  401. void initAnimation() {
  402. if (!mInitialized) {
  403. int numValues = mValues.length;
  404. for (int i = 0; i < numValues; ++i) {
  405. mValues[i].init();
  406. }
  407. mInitialized = true;
  408. }
  409. }
  410. /**
  411. * Sets the length of the animation. The default duration is 300 milliseconds.
  412. *
  413. * @param duration The length of the animation, in milliseconds. This value cannot
  414. * be negative.
  415. * @return ValueAnimator The object called with setDuration(). This return
  416. * value makes it easier to compose statements together that construct and then set the
  417. * duration, as in <code>ValueAnimator.ofInt(0, 10).setDuration(500).start()</code>.
  418. */
  419. public ValueAnimator setDuration(long duration) {
  420. if (duration < 0) {
  421. throw new IllegalArgumentException("Animators cannot have negative duration: " +
  422. duration);
  423. }
  424. mUnscaledDuration = duration;
  425. mDuration = (long)(duration * sDurationScale);
  426. return this;
  427. }
  428. /**
  429. * Gets the length of the animation. The default duration is 300 milliseconds.
  430. *
  431. * @return The length of the animation, in milliseconds.
  432. */
  433. public long getDuration() {
  434. return mUnscaledDuration;
  435. }
  436. /**
  437. * Sets the position of the animation to the specified point in time. This time should
  438. * be between 0 and the total duration of the animation, including any repetition. If
  439. * the animation has not yet been started, then it will not advance forward after it is
  440. * set to this time; it will simply set the time to this value and perform any appropriate
  441. * actions based on that time. If the animation is already running, then setCurrentPlayTime()
  442. * will set the current playing time to this value and continue playing from that point.
  443. *
  444. * @param playTime The time, in milliseconds, to which the animation is advanced or rewound.
  445. */
  446. public void setCurrentPlayTime(long playTime) {
  447. initAnimation();
  448. long currentTime = AnimationUtils.currentAnimationTimeMillis();
  449. if (mPlayingState != RUNNING) {
  450. mSeekTime = playTime;
  451. mPlayingState = SEEKED;
  452. }
  453. mStartTime = currentTime - playTime;
  454. doAnimationFrame(currentTime);
  455. }
  456. /**
  457. * Gets the current position of the animation in time, which is equal to the current
  458. * time minus the time that the animation started. An animation that is not yet started will
  459. * return a value of zero.
  460. *
  461. * @return The current position in time of the animation.
  462. */
  463. public long getCurrentPlayTime() {
  464. if (!mInitialized || mPlayingState == STOPPED) {
  465. return 0;
  466. }
  467. return AnimationUtils.currentAnimationTimeMillis() - mStartTime;
  468. }
  469. /**
  470. * This custom, static handler handles the timing pulse that is shared by
  471. * all active animations. This approach ensures that the setting of animation
  472. * values will happen on the UI thread and that all animations will share
  473. * the same times for calculating their values, which makes synchronizing
  474. * animations possible.
  475. *
  476. * The handler uses the Choreographer for executing periodic callbacks.
  477. */
  478. private static class AnimationHandler implements Runnable {
  479. // The per-thread list of all active animations
  480. private final ArrayList<ValueAnimator> mAnimations = new ArrayList<ValueAnimator>();
  481. // The per-thread set of animations to be started on the next animation frame
  482. private final ArrayList<ValueAnimator> mPendingAnimations = new ArrayList<ValueAnimator>();
  483. /**
  484. * Internal per-thread collections used to avoid set collisions as animations start and end
  485. * while being processed.
  486. */
  487. private final ArrayList<ValueAnimator> mDelayedAnims = new ArrayList<ValueAnimator>();
  488. private final ArrayList<ValueAnimator> mEndingAnims = new ArrayList<ValueAnimator>();
  489. private final ArrayList<ValueAnimator> mReadyAnims = new ArrayList<ValueAnimator>();
  490. private final Choreographer mChoreographer;
  491. private boolean mAnimationScheduled;
  492. private AnimationHandler() {
  493. mChoreographer = Choreographer.getInstance();
  494. }
  495. /**
  496. * Start animating on the next frame.
  497. */
  498. public void start() {
  499. scheduleAnimation();
  500. }
  501. private void doAnimationFrame(long frameTime) {
  502. // mPendingAnimations holds any animations that have requested to be started
  503. // We're going to clear mPendingAnimations, but starting animation may
  504. // cause more to be added to the pending list (for example, if one animation
  505. // starting triggers another starting). So we loop until mPendingAnimations
  506. // is empty.
  507. while (mPendingAnimations.size() > 0) {
  508. ArrayList<ValueAnimator> pendingCopy =
  509. (ArrayList<ValueAnimator>) mPendingAnimations.clone();
  510. mPendingAnimations.clear();
  511. int count = pendingCopy.size();
  512. for (int i = 0; i < count; ++i) {
  513. ValueAnimator anim = pendingCopy.get(i);
  514. // If the animation has a startDelay, place it on the delayed list
  515. if (anim.mStartDelay == 0) {
  516. anim.startAnimation(this);
  517. } else {
  518. mDelayedAnims.add(anim);
  519. }
  520. }
  521. }
  522. // Next, process animations currently sitting on the delayed queue, adding
  523. // them to the active animations if they are ready
  524. int numDelayedAnims = mDelayedAnims.size();
  525. for (int i = 0; i < numDelayedAnims; ++i) {
  526. ValueAnimator anim = mDelayedAnims.get(i);
  527. if (anim.delayedAnimationFrame(frameTime)) {
  528. mReadyAnims.add(anim);
  529. }
  530. }
  531. int numReadyAnims = mReadyAnims.size();
  532. if (numReadyAnims > 0) {
  533. for (int i = 0; i < numReadyAnims; ++i) {
  534. ValueAnimator anim = mReadyAnims.get(i);
  535. anim.startAnimation(this);
  536. anim.mRunning = true;
  537. mDelayedAnims.remove(anim);
  538. }
  539. mReadyAnims.clear();
  540. }
  541. // Now process all active animations. The return value from animationFrame()
  542. // tells the handler whether it should now be ended
  543. int numAnims = mAnimations.size();
  544. int i = 0;
  545. while (i < numAnims) {
  546. ValueAnimator anim = mAnimations.get(i);
  547. if (anim.doAnimationFrame(frameTime)) {
  548. mEndingAnims.add(anim);
  549. }
  550. if (mAnimations.size() == numAnims) {
  551. ++i;
  552. } else {
  553. // An animation might be canceled or ended by client code
  554. // during the animation frame. Check to see if this happened by
  555. // seeing whether the current index is the same as it was before
  556. // calling animationFrame(). Another approach would be to copy
  557. // animations to a temporary list and process that list instead,
  558. // but that entails garbage and processing overhead that would
  559. // be nice to avoid.
  560. --numAnims;
  561. mEndingAnims.remove(anim);
  562. }
  563. }
  564. if (mEndingAnims.size() > 0) {
  565. for (i = 0; i < mEndingAnims.size(); ++i) {
  566. mEndingAnims.get(i).endAnimation(this);
  567. }
  568. mEndingAnims.clear();
  569. }
  570. // If there are still active or delayed animations, schedule a future call to
  571. // onAnimate to process the next frame of the animations.
  572. if (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty()) {
  573. scheduleAnimation();
  574. }
  575. }
  576. // Called by the Choreographer.
  577. @Override
  578. public void run() {
  579. mAnimationScheduled = false;
  580. doAnimationFrame(mChoreographer.getFrameTime());
  581. }
  582. private void scheduleAnimation() {
  583. if (!mAnimationScheduled) {
  584. mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
  585. mAnimationScheduled = true;
  586. }
  587. }
  588. }
  589. /**
  590. * The amount of time, in milliseconds, to delay starting the animation after
  591. * {@link #start()} is called.
  592. *
  593. * @return the number of milliseconds to delay running the animation
  594. */
  595. public long getStartDelay() {
  596. return mUnscaledStartDelay;
  597. }
  598. /**
  599. * The amount of time, in milliseconds, to delay starting the animation after
  600. * {@link #start()} is called.
  601. * @param startDelay The amount of the delay, in milliseconds
  602. */
  603. public void setStartDelay(long startDelay) {
  604. this.mStartDelay = (long)(startDelay * sDurationScale);
  605. mUnscaledStartDelay = startDelay;
  606. }
  607. /**
  608. * The amount of time, in milliseconds, between each frame of the animation. This is a
  609. * requested time that the animation will attempt to honor, but the actual delay between
  610. * frames may be different, depending on system load and capabilities. This is a static
  611. * function because the same delay will be applied to all animations, since they are all
  612. * run off of a single timing loop.
  613. *
  614. * The frame delay may be ignored when the animation system uses an external timing
  615. * source, such as the display refresh rate (vsync), to govern animations.
  616. *
  617. * @return the requested time between frames, in milliseconds
  618. */
  619. public static long getFrameDelay() {
  620. return Choreographer.getFrameDelay();
  621. }
  622. /**
  623. * The amount of time, in milliseconds, between each frame of the animation. This is a
  624. * requested time that the animation will attempt to honor, but the actual delay between
  625. * frames may be different, depending on system load and capabilities. This is a static
  626. * function because the same delay will be applied to all animations, since they are all
  627. * run off of a single timing loop.
  628. *
  629. * The frame delay may be ignored when the animation system uses an external timing
  630. * source, such as the display refresh rate (vsync), to govern animations.
  631. *
  632. * @param frameDelay the requested time between frames, in milliseconds
  633. */
  634. public static void setFrameDelay(long frameDelay) {
  635. Choreographer.setFrameDelay(frameDelay);
  636. }
  637. /**
  638. * The most recent value calculated by this <code>ValueAnimator</code> when there is just one
  639. * property being animated. This value is only sensible while the animation is running. The main
  640. * purpose for this read-only property is to retrieve the value from the <code>ValueAnimator</code>
  641. * during a call to {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)}, which
  642. * is called during each animation frame, immediately after the value is calculated.
  643. *
  644. * @return animatedValue The value most recently calculated by this <code>ValueAnimator</code> for
  645. * the single property being animated. If there are several properties being animated
  646. * (specified by several PropertyValuesHolder objects in the constructor), this function
  647. * returns the animated value for the first of those objects.
  648. */
  649. public Object getAnimatedValue() {
  650. if (mValues != null && mValues.length > 0) {
  651. return mValues[0].getAnimatedValue();
  652. }
  653. // Shouldn't get here; should always have values unless ValueAnimator was set up wrong
  654. return null;
  655. }
  656. /**
  657. * The most recent value calculated by this <code>ValueAnimator</code> for <code>propertyName</code>.
  658. * The main purpose for this read-only property is to retrieve the value from the
  659. * <code>ValueAnimator</code> during a call to
  660. * {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)}, which
  661. * is called during each animation frame, immediately after the value is calculated.
  662. *
  663. * @return animatedValue The value most recently calculated for the named property
  664. * by this <code>ValueAnimator</code>.
  665. */
  666. public Object getAnimatedValue(String propertyName) {
  667. PropertyValuesHolder valuesHolder = mValuesMap.get(propertyName);
  668. if (valuesHolder != null) {
  669. return valuesHolder.getAnimatedValue();
  670. } else {
  671. // At least avoid crashing if called with bogus propertyName
  672. return null;
  673. }
  674. }
  675. /**
  676. * Sets how many times the animation should be repeated. If the repeat
  677. * count is 0, the animation is never repeated. If the repeat count is
  678. * greater than 0 or {@link #INFINITE}, the repeat mode will be taken
  679. * into account. The repeat count is 0 by default.
  680. *
  681. * @param value the number of times the animation should be repeated
  682. */
  683. public void setRepeatCount(int value) {
  684. mRepeatCount = value;
  685. }
  686. /**
  687. * Defines how many times the animation should repeat. The default value
  688. * is 0.
  689. *
  690. * @return the number of times the animation should repeat, or {@link #INFINITE}
  691. */
  692. public int getRepeatCount() {
  693. return mRepeatCount;
  694. }
  695. /**
  696. * Defines what this animation should do when it reaches the end. This
  697. * setting is applied only when the repeat count is either greater than
  698. * 0 or {@link #INFINITE}. Defaults to {@link #RESTART}.
  699. *
  700. * @param value {@link #RESTART} or {@link #REVERSE}
  701. */
  702. public void setRepeatMode(int value) {
  703. mRepeatMode = value;
  704. }
  705. /**
  706. * Defines what this animation should do when it reaches the end.
  707. *
  708. * @return either one of {@link #REVERSE} or {@link #RESTART}
  709. */
  710. public int getRepeatMode() {
  711. return mRepeatMode;
  712. }
  713. /**
  714. * Adds a listener to the set of listeners that are sent update events through the life of
  715. * an animation. This method is called on all listeners for every frame of the animation,
  716. * after the values for the animation have been calculated.
  717. *
  718. * @param listener the listener to be added to the current set of listeners for this animation.
  719. */
  720. public void addUpdateListener(AnimatorUpdateListener listener) {
  721. if (mUpdateListeners == null) {
  722. mUpdateListeners = new ArrayList<AnimatorUpdateListener>();
  723. }
  724. mUpdateListeners.add(listener);
  725. }
  726. /**
  727. * Removes all listeners from the set listening to frame updates for this animation.
  728. */
  729. public void removeAllUpdateListeners() {
  730. if (mUpdateListeners == null) {
  731. return;
  732. }
  733. mUpdateListeners.clear();
  734. mUpdateListeners = null;
  735. }
  736. /**
  737. * Removes a listener from the set listening to frame updates for this animation.
  738. *
  739. * @param listener the listener to be removed from the current set of update listeners
  740. * for this animation.
  741. */
  742. public void removeUpdateListener(AnimatorUpdateListener listener) {
  743. if (mUpdateListeners == null) {
  744. return;
  745. }
  746. mUpdateListeners.remove(listener);
  747. if (mUpdateListeners.size() == 0) {
  748. mUpdateListeners = null;
  749. }
  750. }
  751. /**
  752. * The time interpolator used in calculating the elapsed fraction of this animation. The
  753. * interpolator determines whether the animation runs with linear or non-linear motion,
  754. * such as acceleration and deceleration. The default value is
  755. * {@link android.view.animation.AccelerateDecelerateInterpolator}
  756. *
  757. * @param value the interpolator to be used by this animation. A value of <code>null</code>
  758. * will result in linear interpolation.
  759. */
  760. @Override
  761. public void setInterpolator(TimeInterpolator value) {
  762. if (value != null) {
  763. mInterpolator = value;
  764. } else {
  765. mInterpolator = new LinearInterpolator();
  766. }
  767. }
  768. /**
  769. * Returns the timing interpolator that this ValueAnimator uses.
  770. *
  771. * @return The timing interpolator for this ValueAnimator.
  772. */
  773. public TimeInterpolator getInterpolator() {
  774. return mInterpolator;
  775. }
  776. /**
  777. * The type evaluator to be used when calculating the animated values of this animation.
  778. * The system will automatically assign a float or int evaluator based on the type
  779. * of <code>startValue</code> and <code>endValue</code> in the constructor. But if these values
  780. * are not one of these primitive types, or if different evaluation is desired (such as is
  781. * necessary with int values that represent colors), a custom evaluator needs to be assigned.
  782. * For example, when running an animation on color values, the {@link ArgbEvaluator}
  783. * should be used to get correct RGB color interpolation.
  784. *
  785. * <p>If this ValueAnimator has only one set of values being animated between, this evaluator
  786. * will be used for that set. If there are several sets of values being animated, which is
  787. * the case if PropertyValuesHOlder objects were set on the ValueAnimator, then the evaluator
  788. * is assigned just to the first PropertyValuesHolder object.</p>
  789. *
  790. * @param value the evaluator to be used this animation
  791. */
  792. public void setEvaluator(TypeEvaluator value) {
  793. if (value != null && mValues != null && mValues.length > 0) {
  794. mValues[0].setEvaluator(value);
  795. }
  796. }
  797. private void notifyStartListeners() {
  798. if (mListeners != null && !mStartListenersCalled) {
  799. ArrayList<AnimatorListener> tmpListeners =
  800. (ArrayList<AnimatorListener>) mListeners.clone();
  801. int numListeners = tmpListeners.size();
  802. for (int i = 0; i < numListeners; ++i) {
  803. tmpListeners.get(i).onAnimationStart(this);
  804. }
  805. }
  806. mStartListenersCalled = true;
  807. }
  808. /**
  809. * Start the animation playing. This version of start() takes a boolean flag that indicates
  810. * whether the animation should play in reverse. The flag is usually false, but may be set
  811. * to true if called from the reverse() method.
  812. *
  813. * <p>The animation started by calling this method will be run on the thread that called
  814. * this method. This thread should have a Looper on it (a runtime exception will be thrown if
  815. * this is not the case). Also, if the animation will animate
  816. * properties of objects in the view hierarchy, then the calling thread should be the UI
  817. * thread for that view hierarchy.</p>
  818. *
  819. * @param playBackwards Whether the ValueAnimator should start playing in reverse.
  820. */
  821. private void start(boolean playBackwards) {
  822. if (Looper.myLooper() == null) {
  823. throw new AndroidRuntimeException("Animators may only be run on Looper threads");
  824. }
  825. mPlayingBackwards = playBackwards;
  826. mCurrentIteration = 0;
  827. mPlayingState = STOPPED;
  828. mStarted = true;
  829. mStartedDelay = false;
  830. AnimationHandler animationHandler = getOrCreateAnimationHandler();
  831. animationHandler.mPendingAnimations.add(this);
  832. if (mStartDelay == 0) {
  833. // This sets the initial value of the animation, prior to actually starting it running
  834. setCurrentPlayTime(0);
  835. mPlayingState = STOPPED;
  836. mRunning = true;
  837. notifyStartListeners();
  838. }
  839. animationHandler.start();
  840. }
  841. @Override
  842. public void start() {
  843. start(false);
  844. }
  845. @Override
  846. public void cancel() {
  847. // Only cancel if the animation is actually running or has been started and is about
  848. // to run
  849. AnimationHandler handler = getOrCreateAnimationHandler();
  850. if (mPlayingState != STOPPED
  851. || handler.mPendingAnimations.contains(this)
  852. || handler.mDelayedAnims.contains(this)) {
  853. // Only notify listeners if the animator has actually started
  854. if ((mStarted || mRunning) && mListeners != null) {
  855. if (!mRunning) {
  856. // If it's not yet running, then start listeners weren't called. Call them now.
  857. notifyStartListeners();
  858. }
  859. ArrayList<AnimatorListener> tmpListeners =
  860. (ArrayList<AnimatorListener>) mListeners.clone();
  861. for (AnimatorListener listener : tmpListeners) {
  862. listener.onAnimationCancel(this);
  863. }
  864. }
  865. endAnimation(handler);
  866. }
  867. }
  868. @Override
  869. public void end() {
  870. AnimationHandler handler = getOrCreateAnimationHandler();
  871. if (!handler.mAnimations.contains(this) && !handler.mPendingAnimations.contains(this)) {
  872. // Special case if the animation has not yet started; get it ready for ending
  873. mStartedDelay = false;
  874. startAnimation(handler);
  875. mStarted = true;
  876. } else if (!mInitialized) {
  877. initAnimation();
  878. }
  879. // The final value set on the target varies, depending on whether the animation
  880. // was supposed to repeat an odd number of times
  881. if (mRepeatCount > 0 && (mRepeatCount & 0x01) == 1) {
  882. animateValue(0f);
  883. } else {
  884. animateValue(1f);
  885. }
  886. endAnimation(handler);
  887. }
  888. @Override
  889. public boolean isRunning() {
  890. return (mPlayingState == RUNNING || mRunning);
  891. }
  892. @Override
  893. public boolean isStarted() {
  894. return mStarted;
  895. }
  896. /**
  897. * Plays the ValueAnimator in reverse. If the animation is already running,
  898. * it will stop itself and play backwards from the point reached when reverse was called.
  899. * If the animation is not currently running, then it will start from the end and
  900. * play backwards. This behavior is only set for the current animation; future playing
  901. * of the animation will use the default behavior of playing forward.
  902. */
  903. public void reverse() {
  904. mPlayingBackwards = !mPlayingBackwards;
  905. if (mPlayingState == RUNNING) {
  906. long currentTime = AnimationUtils.currentAnimationTimeMillis();
  907. long currentPlayTime = currentTime - mStartTime;
  908. long timeLeft = mDuration - currentPlayTime;
  909. mStartTime = currentTime - timeLeft;
  910. } else {
  911. start(true);
  912. }
  913. }
  914. /**
  915. * Called internally to end an animation by removing it from the animations list. Must be
  916. * called on the UI thread.
  917. */
  918. private void endAnimation(AnimationHandler handler) {
  919. handler.mAnimations.remove(this);
  920. handler.mPendingAnimations.remove(this);
  921. handler.mDelayedAnims.remove(this);
  922. mPlayingState = STOPPED;
  923. if ((mStarted || mRunning) && mListeners != null) {
  924. if (!mRunning) {
  925. // If it's not yet running, then start listeners weren't called. Call them now.
  926. notifyStartListeners();
  927. }
  928. ArrayList<AnimatorListener> tmpListeners =
  929. (ArrayList<AnimatorListener>) mListeners.clone();
  930. int numListeners = tmpListeners.size();
  931. for (int i = 0; i < numListeners; ++i) {
  932. tmpListeners.get(i).onAnimationEnd(this);
  933. }
  934. }
  935. mRunning = false;
  936. mStarted = false;
  937. mStartListenersCalled = false;
  938. }
  939. /**
  940. * Called internally to start an animation by adding it to the active animations list. Must be
  941. * called on the UI thread.
  942. */
  943. private void startAnimation(AnimationHandler handler) {
  944. initAnimation();
  945. handler.mAnimations.add(this);
  946. if (mStartDelay > 0 && mListeners != null) {
  947. // Listeners were already notified in start() if startDelay is 0; this is
  948. // just for delayed animations
  949. notifyStartListeners();
  950. }
  951. }
  952. /**
  953. * Internal function called to process an animation frame on an animation that is currently
  954. * sleeping through its <code>startDelay</code> phase. The return value indicates whether it
  955. * should be woken up and put on the active animations queue.
  956. *
  957. * @param currentTime The current animation time, used to calculate whether the animation
  958. * has exceeded its <code>startDelay</code> and should be started.
  959. * @return True if the animation's <code>startDelay</code> has been exceeded and the animation
  960. * should be added to the set of active animations.
  961. */
  962. private boolean delayedAnimationFrame(long currentTime) {
  963. if (!mStartedDelay) {
  964. mStartedDelay = true;
  965. mDelayStartTime = currentTime;
  966. } else {
  967. long deltaTime = currentTime - mDelayStartTime;
  968. if (deltaTime > mStartDelay) {
  969. // startDelay ended - start the anim and record the
  970. // mStartTime appropriately
  971. mStartTime = currentTime - (deltaTime - mStartDelay);
  972. mPlayingState = RUNNING;
  973. return true;
  974. }
  975. }
  976. return false;
  977. }
  978. /**
  979. * This internal function processes a single animation frame for a given animation. The
  980. * currentTime parameter is the timing pulse sent by the handler, used to calculate the
  981. * elapsed duration, and therefore
  982. * the elapsed fraction, of the animation. The return value indicates whether the animation
  983. * should be ended (which happens when the elapsed time of the animation exceeds the
  984. * animation's duration, including the repeatCount).
  985. *
  986. * @param currentTime The current time, as tracked by the static timing handler
  987. * @return true if the animation's duration, including any repetitions due to
  988. * <code>repeatCount</code> has been exceeded and the animation should be ended.
  989. */
  990. boolean animationFrame(long currentTime) {
  991. boolean done = false;
  992. switch (mPlayingState) {
  993. case RUNNING:
  994. case SEEKED:
  995. float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f;
  996. if (fraction >= 1f) {
  997. if (mCurrentIteration < mRepeatCount || mRepeatCount == INFINITE) {
  998. // Time to repeat
  999. if (mListeners != null) {
  1000. int numListeners = mListeners.size();
  1001. for (int i = 0; i < numListeners; ++i) {
  1002. mListeners.get(i).onAnimationRepeat(this);
  1003. }
  1004. }
  1005. if (mRepeatMode == REVERSE) {
  1006. mPlayingBackwards = mPlayingBackwards ? false : true;
  1007. }
  1008. mCurrentIteration += (int)fraction;
  1009. fraction = fraction % 1f;
  1010. mStartTime += mDuration;
  1011. } else {
  1012. done = true;
  1013. fraction = Math.min(fraction, 1.0f);
  1014. }
  1015. }
  1016. if (mPlayingBackwards) {
  1017. fraction = 1f - fraction;
  1018. }
  1019. animateValue(fraction);
  1020. break;
  1021. }
  1022. return done;
  1023. }
  1024. /**
  1025. * Processes a frame of the animation, adjusting the start time if needed.
  1026. *
  1027. * @param frameTime The frame time.
  1028. * @return true if the animation has ended.
  1029. */
  1030. final boolean doAnimationFrame(long frameTime) {
  1031. if (mPlayingState == STOPPED) {
  1032. mPlayingState = RUNNING;
  1033. if (mSeekTime < 0) {
  1034. mStartTime = frameTime;
  1035. } else {
  1036. mStartTime = frameTime - mSeekTime;
  1037. // Now that we're playing, reset the seek time
  1038. mSeekTime = -1;
  1039. }
  1040. }
  1041. // The frame time might be before the start time during the first frame of
  1042. // an animation. The "current time" must always be on or after the start
  1043. // time to avoid animating frames at negative time intervals. In practice, this
  1044. // is very rare and only happens when seeking backwards.
  1045. final long currentTime = Math.max(frameTime, mStartTime);
  1046. return animationFrame(currentTime);
  1047. }
  1048. /**
  1049. * Returns the current animation fraction, which is the elapsed/interpolated fraction used in
  1050. * the most recent frame update on the animation.
  1051. *
  1052. * @return Elapsed/interpolated fraction of the animation.
  1053. */
  1054. public float getAnimatedFraction() {
  1055. return mCurrentFraction;
  1056. }
  1057. /**
  1058. * This method is called with the elapsed fraction of the animation during every
  1059. * animation frame. This function turns the elapsed fraction into an interpolated fraction
  1060. * and then into an animated value (from the evaluator. The function is called mostly during
  1061. * animation updates, but it is also called when the <code>end()</code>
  1062. * function is called, to set the final value on the property.
  1063. *
  1064. * <p>Overrides of this method must call the superclass to perform the calculation
  1065. * of the animated value.</p>
  1066. *
  1067. * @param fraction The elapsed fraction of the animation.
  1068. */
  1069. void animateValue(float fraction) {
  1070. fraction = mInterpolator.getInterpolation(fraction);
  1071. mCurrentFraction = fraction;
  1072. int numValues = mValues.length;
  1073. for (int i = 0; i < numValues; ++i) {
  1074. mValues[i].calculateValue(fraction);
  1075. }
  1076. if (mUpdateListeners != null) {
  1077. int numListeners = mUpdateListeners.size();
  1078. for (int i = 0; i < numListeners; ++i) {
  1079. mUpdateListeners.get(i).onAnimationUpdate(this);
  1080. }
  1081. }
  1082. }
  1083. @Override
  1084. public ValueAnimator clone() {
  1085. final ValueAnimator anim = (ValueAnimator) super.clone();
  1086. if (mUpdateListeners != null) {
  1087. ArrayList<AnimatorUpdateListener> oldListeners = mUpdateListeners;
  1088. anim.mUpdateListeners = new ArrayList<AnimatorUpdateListener>();
  1089. int numListeners = oldListeners.size();
  1090. for (int i = 0; i < numListeners; ++i) {
  1091. anim.mUpdateListeners.add(oldListeners.get(i));
  1092. }
  1093. }
  1094. anim.mSeekTime = -1;
  1095. anim.mPlayingBackwards = false;
  1096. anim.mCurrentIteration = 0;
  1097. anim.mInitialized = false;
  1098. anim.mPlayingState = STOPPED;
  1099. anim.mStartedDelay = false;
  1100. PropertyValuesHolder[] oldValues = mValues;
  1101. if (oldValues != null) {
  1102. int numValues = oldValues.length;
  1103. anim.mValues = new PropertyValuesHolder[numValues];
  1104. anim.mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
  1105. for (int i = 0; i < numValues; ++i) {
  1106. PropertyValuesHolder newValuesHolder = oldValues[i].clone();
  1107. anim.mValues[i] = newValuesHolder;

Large files files are truncated, but you can click here to view the full file