• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.TestApi;
22 import android.compat.annotation.UnsupportedAppUsage;
23 import android.content.pm.ActivityInfo.Config;
24 import android.content.res.ConstantState;
25 import android.os.Build;
26 import android.util.LongArray;
27 
28 import java.util.ArrayList;
29 import java.util.concurrent.atomic.AtomicReference;
30 
31 /**
32  * This is the superclass for classes which provide basic support for animations which can be
33  * started, ended, and have <code>AnimatorListeners</code> added to them.
34  */
35 public abstract class Animator implements Cloneable {
36 
37     /**
38      * The value used to indicate infinite duration (e.g. when Animators repeat infinitely).
39      */
40     public static final long DURATION_INFINITE = -1;
41     /**
42      * The set of listeners to be sent events through the life of an animation.
43      */
44     ArrayList<AnimatorListener> mListeners = null;
45 
46     /**
47      * The set of listeners to be sent pause/resume events through the life
48      * of an animation.
49      */
50     ArrayList<AnimatorPauseListener> mPauseListeners = null;
51 
52     /**
53      * Whether this animator is currently in a paused state.
54      */
55     boolean mPaused = false;
56 
57     /**
58      * A set of flags which identify the type of configuration changes that can affect this
59      * Animator. Used by the Animator cache.
60      */
61     @Config int mChangingConfigurations = 0;
62 
63     /**
64      * If this animator is inflated from a constant state, keep a reference to it so that
65      * ConstantState will not be garbage collected until this animator is collected
66      */
67     private AnimatorConstantState mConstantState;
68 
69     /**
70      * backing field for backgroundPauseDelay property. This could be simply a hardcoded
71      * value in AnimationHandler, but it is useful to be able to change the value in tests.
72      */
73     private static long sBackgroundPauseDelay = 1000;
74 
75     /**
76      * A cache of the values in a list. Used so that when calling the list, we have a copy
77      * of it in case the list is modified while iterating. The array can be reused to avoid
78      * allocation on every notification.
79      */
80     private AtomicReference<Object[]> mCachedList = new AtomicReference<>();
81 
82     /**
83      * Tracks whether we've notified listeners of the onAnimationStart() event. This can be
84      * complex to keep track of since we notify listeners at different times depending on
85      * startDelay and whether start() was called before end().
86      */
87     boolean mStartListenersCalled = false;
88 
89     /**
90      * Sets the duration for delaying pausing animators when apps go into the background.
91      * Used by AnimationHandler when requested to pause animators.
92      *
93      * @hide
94      */
95     @TestApi
setBackgroundPauseDelay(long value)96     public static void setBackgroundPauseDelay(long value) {
97         sBackgroundPauseDelay = value;
98     }
99 
100     /**
101      * Gets the duration for delaying pausing animators when apps go into the background.
102      * Used by AnimationHandler when requested to pause animators.
103      *
104      * @hide
105      */
106     @TestApi
getBackgroundPauseDelay()107     public static long getBackgroundPauseDelay() {
108         return sBackgroundPauseDelay;
109     }
110 
111     /**
112      * Sets the behavior of animator pausing when apps go into the background.
113      * This is exposed as a test API for verification, but is intended for use by internal/
114      * platform code, potentially for use by a system property that could disable it
115      * system wide.
116      *
117      * @param enable Enable (default behavior) or disable background pausing behavior.
118      * @hide
119      */
120     @TestApi
setAnimatorPausingEnabled(boolean enable)121     public static void setAnimatorPausingEnabled(boolean enable) {
122         AnimationHandler.setAnimatorPausingEnabled(enable);
123         AnimationHandler.setOverrideAnimatorPausingSystemProperty(!enable);
124     }
125 
126     /**
127      * Starts this animation. If the animation has a nonzero startDelay, the animation will start
128      * running after that delay elapses. A non-delayed animation will have its initial
129      * value(s) set immediately, followed by calls to
130      * {@link AnimatorListener#onAnimationStart(Animator)} for any listeners of this animator.
131      *
132      * <p>The animation started by calling this method will be run on the thread that called
133      * this method. This thread should have a Looper on it (a runtime exception will be thrown if
134      * this is not the case). Also, if the animation will animate
135      * properties of objects in the view hierarchy, then the calling thread should be the UI
136      * thread for that view hierarchy.</p>
137      *
138      */
start()139     public void start() {
140     }
141 
142     /**
143      * Cancels the animation. Unlike {@link #end()}, <code>cancel()</code> causes the animation to
144      * stop in its tracks, sending an
145      * {@link android.animation.Animator.AnimatorListener#onAnimationCancel(Animator)} to
146      * its listeners, followed by an
147      * {@link android.animation.Animator.AnimatorListener#onAnimationEnd(Animator)} message.
148      *
149      * <p>This method must be called on the thread that is running the animation.</p>
150      */
cancel()151     public void cancel() {
152     }
153 
154     /**
155      * Ends the animation. This causes the animation to assign the end value of the property being
156      * animated, then calling the
157      * {@link android.animation.Animator.AnimatorListener#onAnimationEnd(Animator)} method on
158      * its listeners.
159      *
160      * <p>This method must be called on the thread that is running the animation.</p>
161      */
end()162     public void end() {
163     }
164 
165     /**
166      * Pauses a running animation. This method should only be called on the same thread on
167      * which the animation was started. If the animation has not yet been {@link
168      * #isStarted() started} or has since ended, then the call is ignored. Paused
169      * animations can be resumed by calling {@link #resume()}.
170      *
171      * @see #resume()
172      * @see #isPaused()
173      * @see AnimatorPauseListener
174      */
pause()175     public void pause() {
176         // We only want to pause started Animators or animators that setCurrentPlayTime()
177         // have been called on. mStartListenerCalled will be true if seek has happened.
178         if ((isStarted() || mStartListenersCalled) && !mPaused) {
179             mPaused = true;
180             notifyPauseListeners(AnimatorCaller.ON_PAUSE);
181         }
182     }
183 
184     /**
185      * Resumes a paused animation, causing the animator to pick up where it left off
186      * when it was paused. This method should only be called on the same thread on
187      * which the animation was started. Calls to resume() on an animator that is
188      * not currently paused will be ignored.
189      *
190      * @see #pause()
191      * @see #isPaused()
192      * @see AnimatorPauseListener
193      */
resume()194     public void resume() {
195         if (mPaused) {
196             mPaused = false;
197             notifyPauseListeners(AnimatorCaller.ON_RESUME);
198         }
199     }
200 
201     /**
202      * Returns whether this animator is currently in a paused state.
203      *
204      * @return True if the animator is currently paused, false otherwise.
205      *
206      * @see #pause()
207      * @see #resume()
208      */
isPaused()209     public boolean isPaused() {
210         return mPaused;
211     }
212 
213     /**
214      * The amount of time, in milliseconds, to delay processing the animation
215      * after {@link #start()} is called.
216      *
217      * @return the number of milliseconds to delay running the animation
218      */
getStartDelay()219     public abstract long getStartDelay();
220 
221     /**
222      * The amount of time, in milliseconds, to delay processing the animation
223      * after {@link #start()} is called.
224 
225      * @param startDelay The amount of the delay, in milliseconds
226      */
setStartDelay(long startDelay)227     public abstract void setStartDelay(long startDelay);
228 
229     /**
230      * Sets the duration of the animation.
231      *
232      * @param duration The length of the animation, in milliseconds.
233      */
setDuration(long duration)234     public abstract Animator setDuration(long duration);
235 
236     /**
237      * Gets the duration of the animation.
238      *
239      * @return The length of the animation, in milliseconds.
240      */
getDuration()241     public abstract long getDuration();
242 
243     /**
244      * Gets the total duration of the animation, accounting for animation sequences, start delay,
245      * and repeating. Return {@link #DURATION_INFINITE} if the duration is infinite.
246      *
247      * @return  Total time an animation takes to finish, starting from the time {@link #start()}
248      *          is called. {@link #DURATION_INFINITE} will be returned if the animation or any
249      *          child animation repeats infinite times.
250      */
getTotalDuration()251     public long getTotalDuration() {
252         long duration = getDuration();
253         if (duration == DURATION_INFINITE) {
254             return DURATION_INFINITE;
255         } else {
256             return getStartDelay() + duration;
257         }
258     }
259 
260     /**
261      * The time interpolator used in calculating the elapsed fraction of the
262      * animation. The interpolator determines whether the animation runs with
263      * linear or non-linear motion, such as acceleration and deceleration. The
264      * default value is {@link android.view.animation.AccelerateDecelerateInterpolator}.
265      *
266      * @param value the interpolator to be used by this animation
267      */
setInterpolator(TimeInterpolator value)268     public abstract void setInterpolator(TimeInterpolator value);
269 
270     /**
271      * Returns the timing interpolator that this animation uses.
272      *
273      * @return The timing interpolator for this animation.
274      */
getInterpolator()275     public TimeInterpolator getInterpolator() {
276         return null;
277     }
278 
279     /**
280      * Returns whether this Animator is currently running (having been started and gone past any
281      * initial startDelay period and not yet ended).
282      *
283      * @return Whether the Animator is running.
284      */
isRunning()285     public abstract boolean isRunning();
286 
287     /**
288      * Returns whether this Animator has been started and not yet ended. For reusable
289      * Animators (which most Animators are, apart from the one-shot animator produced by
290      * {@link android.view.ViewAnimationUtils#createCircularReveal(
291      * android.view.View, int, int, float, float) createCircularReveal()}),
292      * this state is a superset of {@link #isRunning()}, because an Animator with a
293      * nonzero {@link #getStartDelay() startDelay} will return true for {@link #isStarted()} during
294      * the delay phase, whereas {@link #isRunning()} will return true only after the delay phase
295      * is complete. Non-reusable animators will always return true after they have been
296      * started, because they cannot return to a non-started state.
297      *
298      * @return Whether the Animator has been started and not yet ended.
299      */
isStarted()300     public boolean isStarted() {
301         // Default method returns value for isRunning(). Subclasses should override to return a
302         // real value.
303         return isRunning();
304     }
305 
306     /**
307      * Adds a listener to the set of listeners that are sent events through the life of an
308      * animation, such as start, repeat, and end.
309      *
310      * @param listener the listener to be added to the current set of listeners for this animation.
311      */
addListener(AnimatorListener listener)312     public void addListener(AnimatorListener listener) {
313         if (mListeners == null) {
314             mListeners = new ArrayList<AnimatorListener>();
315         }
316         mListeners.add(listener);
317     }
318 
319     /**
320      * Removes a listener from the set listening to this animation.
321      *
322      * @param listener the listener to be removed from the current set of listeners for this
323      *                 animation.
324      */
removeListener(AnimatorListener listener)325     public void removeListener(AnimatorListener listener) {
326         if (mListeners == null) {
327             return;
328         }
329         mListeners.remove(listener);
330         if (mListeners.size() == 0) {
331             mListeners = null;
332         }
333     }
334 
335     /**
336      * Gets the set of {@link android.animation.Animator.AnimatorListener} objects that are currently
337      * listening for events on this <code>Animator</code> object.
338      *
339      * @return ArrayList<AnimatorListener> The set of listeners.
340      */
getListeners()341     public ArrayList<AnimatorListener> getListeners() {
342         return mListeners;
343     }
344 
345     /**
346      * Adds a pause listener to this animator.
347      *
348      * @param listener the listener to be added to the current set of pause listeners
349      * for this animation.
350      */
addPauseListener(AnimatorPauseListener listener)351     public void addPauseListener(AnimatorPauseListener listener) {
352         if (mPauseListeners == null) {
353             mPauseListeners = new ArrayList<AnimatorPauseListener>();
354         }
355         mPauseListeners.add(listener);
356     }
357 
358     /**
359      * Removes a pause listener from the set listening to this animation.
360      *
361      * @param listener the listener to be removed from the current set of pause
362      * listeners for this animation.
363      */
removePauseListener(AnimatorPauseListener listener)364     public void removePauseListener(AnimatorPauseListener listener) {
365         if (mPauseListeners == null) {
366             return;
367         }
368         mPauseListeners.remove(listener);
369         if (mPauseListeners.size() == 0) {
370             mPauseListeners = null;
371         }
372     }
373 
374     /**
375      * Removes all {@link #addListener(android.animation.Animator.AnimatorListener) listeners}
376      * and {@link #addPauseListener(android.animation.Animator.AnimatorPauseListener)
377      * pauseListeners} from this object.
378      */
removeAllListeners()379     public void removeAllListeners() {
380         if (mListeners != null) {
381             mListeners.clear();
382             mListeners = null;
383         }
384         if (mPauseListeners != null) {
385             mPauseListeners.clear();
386             mPauseListeners = null;
387         }
388     }
389 
390     /**
391      * Return a mask of the configuration parameters for which this animator may change, requiring
392      * that it should be re-created from Resources. The default implementation returns whatever
393      * value was provided through setChangingConfigurations(int) or 0 by default.
394      *
395      * @return Returns a mask of the changing configuration parameters, as defined by
396      * {@link android.content.pm.ActivityInfo}.
397      * @see android.content.pm.ActivityInfo
398      * @hide
399      */
getChangingConfigurations()400     public @Config int getChangingConfigurations() {
401         return mChangingConfigurations;
402     }
403 
404     /**
405      * Set a mask of the configuration parameters for which this animator may change, requiring
406      * that it be re-created from resource.
407      *
408      * @param configs A mask of the changing configuration parameters, as
409      * defined by {@link android.content.pm.ActivityInfo}.
410      *
411      * @see android.content.pm.ActivityInfo
412      * @hide
413      */
setChangingConfigurations(@onfig int configs)414     public void setChangingConfigurations(@Config int configs) {
415         mChangingConfigurations = configs;
416     }
417 
418     /**
419      * Sets the changing configurations value to the union of the current changing configurations
420      * and the provided configs.
421      * This method is called while loading the animator.
422      * @hide
423      */
appendChangingConfigurations(@onfig int configs)424     public void appendChangingConfigurations(@Config int configs) {
425         mChangingConfigurations |= configs;
426     }
427 
428     /**
429      * Return a {@link android.content.res.ConstantState} instance that holds the shared state of
430      * this Animator.
431      * <p>
432      * This constant state is used to create new instances of this animator when needed, instead
433      * of re-loading it from resources. Default implementation creates a new
434      * {@link AnimatorConstantState}. You can override this method to provide your custom logic or
435      * return null if you don't want this animator to be cached.
436      *
437      * @return The ConfigurationBoundResourceCache.BaseConstantState associated to this Animator.
438      * @see android.content.res.ConstantState
439      * @see #clone()
440      * @hide
441      */
createConstantState()442     public ConstantState<Animator> createConstantState() {
443         return new AnimatorConstantState(this);
444     }
445 
446     @Override
clone()447     public Animator clone() {
448         try {
449             final Animator anim = (Animator) super.clone();
450             if (mListeners != null) {
451                 anim.mListeners = new ArrayList<AnimatorListener>(mListeners);
452             }
453             if (mPauseListeners != null) {
454                 anim.mPauseListeners = new ArrayList<AnimatorPauseListener>(mPauseListeners);
455             }
456             anim.mCachedList.set(null);
457             anim.mStartListenersCalled = false;
458             return anim;
459         } catch (CloneNotSupportedException e) {
460            throw new AssertionError();
461         }
462     }
463 
464     /**
465      * This method tells the object to use appropriate information to extract
466      * starting values for the animation. For example, a AnimatorSet object will pass
467      * this call to its child objects to tell them to set up the values. A
468      * ObjectAnimator object will use the information it has about its target object
469      * and PropertyValuesHolder objects to get the start values for its properties.
470      * A ValueAnimator object will ignore the request since it does not have enough
471      * information (such as a target object) to gather these values.
472      */
setupStartValues()473     public void setupStartValues() {
474     }
475 
476     /**
477      * This method tells the object to use appropriate information to extract
478      * ending values for the animation. For example, a AnimatorSet object will pass
479      * this call to its child objects to tell them to set up the values. A
480      * ObjectAnimator object will use the information it has about its target object
481      * and PropertyValuesHolder objects to get the start values for its properties.
482      * A ValueAnimator object will ignore the request since it does not have enough
483      * information (such as a target object) to gather these values.
484      */
setupEndValues()485     public void setupEndValues() {
486     }
487 
488     /**
489      * Sets the target object whose property will be animated by this animation. Not all subclasses
490      * operate on target objects (for example, {@link ValueAnimator}, but this method
491      * is on the superclass for the convenience of dealing generically with those subclasses
492      * that do handle targets.
493      * <p>
494      * <strong>Note:</strong> The target is stored as a weak reference internally to avoid leaking
495      * resources by having animators directly reference old targets. Therefore, you should
496      * ensure that animator targets always have a hard reference elsewhere.
497      *
498      * @param target The object being animated
499      */
setTarget(@ullable Object target)500     public void setTarget(@Nullable Object target) {
501     }
502 
503     // Hide reverse() and canReverse() for now since reverse() only work for simple
504     // cases, like we don't support sequential, neither startDelay.
505     // TODO: make reverse() works for all the Animators.
506     /**
507      * @hide
508      */
canReverse()509     public boolean canReverse() {
510         return false;
511     }
512 
513     /**
514      * @hide
515      */
516     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
reverse()517     public void reverse() {
518         throw new IllegalStateException("Reverse is not supported");
519     }
520 
521     // Pulse an animation frame into the animation.
pulseAnimationFrame(long frameTime)522     boolean pulseAnimationFrame(long frameTime) {
523         // TODO: Need to find a better signal than this. There's a bug in SystemUI that's preventing
524         // returning !isStarted() from working.
525         return false;
526     }
527 
528     /**
529      * Internal use only.
530      * This call starts the animation in regular or reverse direction without requiring them to
531      * register frame callbacks. The caller will be responsible for all the subsequent animation
532      * pulses. Specifically, the caller needs to call doAnimationFrame(...) for the animation on
533      * every frame.
534      *
535      * @param inReverse whether the animation should play in reverse direction
536      */
startWithoutPulsing(boolean inReverse)537     void startWithoutPulsing(boolean inReverse) {
538         if (inReverse) {
539             reverse();
540         } else {
541             start();
542         }
543     }
544 
545     /**
546      * Internal use only.
547      * Skips the animation value to end/start, depending on whether the play direction is forward
548      * or backward.
549      *
550      * @param inReverse whether the end value is based on a reverse direction. If yes, this is
551      *                  equivalent to skip to start value in a forward playing direction.
552      */
skipToEndValue(boolean inReverse)553     void skipToEndValue(boolean inReverse) {}
554 
555     /**
556      * Internal use only.
557      *
558      * Returns whether the animation has start/end values setup. For most of the animations, this
559      * should always be true. For ObjectAnimators, the start values are setup in the initialization
560      * of the animation.
561      */
isInitialized()562     boolean isInitialized() {
563         return true;
564     }
565 
566     /**
567      * Internal use only. Changes the value of the animator as if currentPlayTime has passed since
568      * the start of the animation. Therefore, currentPlayTime includes the start delay, and any
569      * repetition. lastPlayTime is similar and is used to calculate how many repeats have been
570      * done between the two times.
571      */
animateValuesInRange(long currentPlayTime, long lastPlayTime)572     void animateValuesInRange(long currentPlayTime, long lastPlayTime) {}
573 
574     /**
575      * Internal use only. This animates any animation that has ended since lastPlayTime.
576      * If an animation hasn't been finished, no change will be made.
577      */
animateSkipToEnds(long currentPlayTime, long lastPlayTime)578     void animateSkipToEnds(long currentPlayTime, long lastPlayTime) {}
579 
580     /**
581      * Internal use only. Adds all start times (after delay) to and end times to times.
582      * The value must include offset.
583      */
getStartAndEndTimes(LongArray times, long offset)584     void getStartAndEndTimes(LongArray times, long offset) {
585         long startTime = offset + getStartDelay();
586         if (times.indexOf(startTime) < 0) {
587             times.add(startTime);
588         }
589         long duration = getTotalDuration();
590         if (duration != DURATION_INFINITE) {
591             long endTime = duration + offset;
592             if (times.indexOf(endTime) < 0) {
593                 times.add(endTime);
594             }
595         }
596     }
597 
598     /**
599      * Calls notification for each AnimatorListener.
600      *
601      * @param notification The notification method to call on each listener.
602      * @param isReverse When this is used with start/end, this is the isReverse parameter. For
603      *                  other calls, this is ignored.
604      */
notifyListeners( AnimatorCaller<AnimatorListener, Animator> notification, boolean isReverse )605     void notifyListeners(
606             AnimatorCaller<AnimatorListener, Animator> notification,
607             boolean isReverse
608     ) {
609         callOnList(mListeners, notification, this, isReverse);
610     }
611 
612     /**
613      * Call pause/resume on each AnimatorPauseListener.
614      *
615      * @param notification Either ON_PAUSE or ON_RESUME to call onPause or onResume on each
616      *                     listener.
617      */
notifyPauseListeners(AnimatorCaller<AnimatorPauseListener, Animator> notification)618     void notifyPauseListeners(AnimatorCaller<AnimatorPauseListener, Animator> notification) {
619         callOnList(mPauseListeners, notification, this, false);
620     }
621 
notifyStartListeners(boolean isReversing)622     void notifyStartListeners(boolean isReversing) {
623         boolean startListenersCalled = mStartListenersCalled;
624         mStartListenersCalled = true;
625         if (mListeners != null && !startListenersCalled) {
626             notifyListeners(AnimatorCaller.ON_START, isReversing);
627         }
628     }
629 
notifyEndListeners(boolean isReversing)630     void notifyEndListeners(boolean isReversing) {
631         boolean startListenersCalled = mStartListenersCalled;
632         mStartListenersCalled = false;
633         if (mListeners != null && startListenersCalled) {
634             notifyListeners(AnimatorCaller.ON_END, isReversing);
635         }
636     }
637 
638     /**
639      * Calls <code>call</code> for every item in <code>list</code> with <code>animator</code> and
640      * <code>isReverse</code> as parameters.
641      *
642      * @param list The list of items to make calls on.
643      * @param call The method to call for each item in list.
644      * @param animator The animator parameter of call.
645      * @param isReverse The isReverse parameter of call.
646      * @param <T> The item type of list
647      * @param <A> The Animator type of animator.
648      */
callOnList( ArrayList<T> list, AnimatorCaller<T, A> call, A animator, boolean isReverse )649     <T, A> void callOnList(
650             ArrayList<T> list,
651             AnimatorCaller<T, A> call,
652             A animator,
653             boolean isReverse
654     ) {
655         int size = list == null ? 0 : list.size();
656         if (size > 0) {
657             // Try to reuse mCacheList to store the items of list.
658             Object[] array = mCachedList.getAndSet(null);
659             if (array == null || array.length < size) {
660                 array = new Object[size];
661             }
662             list.toArray(array);
663             for (int i = 0; i < size; i++) {
664                 //noinspection unchecked
665                 T item = (T) array[i];
666                 call.call(item, animator, isReverse);
667                 array[i] = null;
668             }
669             // Store it for the next call so we can reuse this array, if needed.
670             mCachedList.compareAndSet(null, array);
671         }
672     }
673 
674     /**
675      * <p>An animation listener receives notifications from an animation.
676      * Notifications indicate animation related events, such as the end or the
677      * repetition of the animation.</p>
678      */
679     public static interface AnimatorListener {
680 
681         /**
682          * <p>Notifies the start of the animation as well as the animation's overall play direction.
683          * This method's default behavior is to call {@link #onAnimationStart(Animator)}. This
684          * method can be overridden, though not required, to get the additional play direction info
685          * when an animation starts. Skipping calling super when overriding this method results in
686          * {@link #onAnimationStart(Animator)} not getting called.
687          *
688          * @param animation The started animation.
689          * @param isReverse Whether the animation is playing in reverse.
690          */
onAnimationStart(@onNull Animator animation, boolean isReverse)691         default void onAnimationStart(@NonNull Animator animation, boolean isReverse) {
692             onAnimationStart(animation);
693         }
694 
695         /**
696          * <p>Notifies the end of the animation. This callback is not invoked
697          * for animations with repeat count set to INFINITE.</p>
698          *
699          * <p>This method's default behavior is to call {@link #onAnimationEnd(Animator)}. This
700          * method can be overridden, though not required, to get the additional play direction info
701          * when an animation ends. Skipping calling super when overriding this method results in
702          * {@link #onAnimationEnd(Animator)} not getting called.
703          *
704          * @param animation The animation which reached its end.
705          * @param isReverse Whether the animation is playing in reverse.
706          */
onAnimationEnd(@onNull Animator animation, boolean isReverse)707         default void onAnimationEnd(@NonNull Animator animation, boolean isReverse) {
708             onAnimationEnd(animation);
709         }
710 
711         /**
712          * <p>Notifies the start of the animation.</p>
713          *
714          * @param animation The started animation.
715          */
onAnimationStart(@onNull Animator animation)716         void onAnimationStart(@NonNull Animator animation);
717 
718         /**
719          * <p>Notifies the end of the animation. This callback is not invoked
720          * for animations with repeat count set to INFINITE.</p>
721          *
722          * @param animation The animation which reached its end.
723          */
onAnimationEnd(@onNull Animator animation)724         void onAnimationEnd(@NonNull Animator animation);
725 
726         /**
727          * <p>Notifies the cancellation of the animation. This callback is not invoked
728          * for animations with repeat count set to INFINITE.</p>
729          *
730          * @param animation The animation which was canceled.
731          */
onAnimationCancel(@onNull Animator animation)732         void onAnimationCancel(@NonNull Animator animation);
733 
734         /**
735          * <p>Notifies the repetition of the animation.</p>
736          *
737          * @param animation The animation which was repeated.
738          */
onAnimationRepeat(@onNull Animator animation)739         void onAnimationRepeat(@NonNull Animator animation);
740     }
741 
742     /**
743      * A pause listener receives notifications from an animation when the
744      * animation is {@link #pause() paused} or {@link #resume() resumed}.
745      *
746      * @see #addPauseListener(AnimatorPauseListener)
747      */
748     public static interface AnimatorPauseListener {
749         /**
750          * <p>Notifies that the animation was paused.</p>
751          *
752          * @param animation The animaton being paused.
753          * @see #pause()
754          */
onAnimationPause(@onNull Animator animation)755         void onAnimationPause(@NonNull Animator animation);
756 
757         /**
758          * <p>Notifies that the animation was resumed, after being
759          * previously paused.</p>
760          *
761          * @param animation The animation being resumed.
762          * @see #resume()
763          */
onAnimationResume(@onNull Animator animation)764         void onAnimationResume(@NonNull Animator animation);
765     }
766 
767     /**
768      * <p>Whether or not the Animator is allowed to run asynchronously off of
769      * the UI thread. This is a hint that informs the Animator that it is
770      * OK to run the animation off-thread, however the Animator may decide
771      * that it must run the animation on the UI thread anyway.
772      *
773      * <p>Regardless of whether or not the animation runs asynchronously, all
774      * listener callbacks will be called on the UI thread.</p>
775      *
776      * <p>To be able to use this hint the following must be true:</p>
777      * <ol>
778      * <li>The animator is immutable while {@link #isStarted()} is true. Requests
779      *    to change duration, delay, etc... may be ignored.</li>
780      * <li>Lifecycle callback events may be asynchronous. Events such as
781      *    {@link Animator.AnimatorListener#onAnimationEnd(Animator)} or
782      *    {@link Animator.AnimatorListener#onAnimationRepeat(Animator)} may end up delayed
783      *    as they must be posted back to the UI thread, and any actions performed
784      *    by those callbacks (such as starting new animations) will not happen
785      *    in the same frame.</li>
786      * <li>State change requests ({@link #cancel()}, {@link #end()}, {@link #reverse()}, etc...)
787      *    may be asynchronous. It is guaranteed that all state changes that are
788      *    performed on the UI thread in the same frame will be applied as a single
789      *    atomic update, however that frame may be the current frame,
790      *    the next frame, or some future frame. This will also impact the observed
791      *    state of the Animator. For example, {@link #isStarted()} may still return true
792      *    after a call to {@link #end()}. Using the lifecycle callbacks is preferred over
793      *    queries to {@link #isStarted()}, {@link #isRunning()}, and {@link #isPaused()}
794      *    for this reason.</li>
795      * </ol>
796      * @hide
797      */
setAllowRunningAsynchronously(boolean mayRunAsync)798     public void setAllowRunningAsynchronously(boolean mayRunAsync) {
799         // It is up to subclasses to support this, if they can.
800     }
801 
802     /**
803      * Creates a {@link ConstantState} which holds changing configurations information associated
804      * with the given Animator.
805      * <p>
806      * When {@link #newInstance()} is called, default implementation clones the Animator.
807      */
808     private static class AnimatorConstantState extends ConstantState<Animator> {
809 
810         final Animator mAnimator;
811         @Config int mChangingConf;
812 
AnimatorConstantState(Animator animator)813         public AnimatorConstantState(Animator animator) {
814             mAnimator = animator;
815             // ensure a reference back to here so that constante state is not gc'ed.
816             mAnimator.mConstantState = this;
817             mChangingConf = mAnimator.getChangingConfigurations();
818         }
819 
820         @Override
getChangingConfigurations()821         public @Config int getChangingConfigurations() {
822             return mChangingConf;
823         }
824 
825         @Override
newInstance()826         public Animator newInstance() {
827             final Animator clone = mAnimator.clone();
828             clone.mConstantState = this;
829             return clone;
830         }
831     }
832 
833     /**
834      * Internally used by {@link #callOnList(ArrayList, AnimatorCaller, Object, boolean)} to
835      * make a call on all children of a list. This can be for start, stop, pause, cancel, update,
836      * etc notifications.
837      *
838      * @param <T> The type of listener to make the call on
839      * @param <A> The type of animator that is passed as a parameter
840      */
841     interface AnimatorCaller<T, A> {
call(T listener, A animator, boolean isReverse)842         void call(T listener, A animator, boolean isReverse);
843 
844         AnimatorCaller<AnimatorListener, Animator> ON_START = AnimatorListener::onAnimationStart;
845         AnimatorCaller<AnimatorListener, Animator> ON_END = AnimatorListener::onAnimationEnd;
846         AnimatorCaller<AnimatorListener, Animator> ON_CANCEL =
847                 (listener, animator, isReverse) -> listener.onAnimationCancel(animator);
848         AnimatorCaller<AnimatorListener, Animator> ON_REPEAT =
849                 (listener, animator, isReverse) -> listener.onAnimationRepeat(animator);
850         AnimatorCaller<AnimatorPauseListener, Animator> ON_PAUSE =
851                 (listener, animator, isReverse) -> listener.onAnimationPause(animator);
852         AnimatorCaller<AnimatorPauseListener, Animator> ON_RESUME =
853                 (listener, animator, isReverse) -> listener.onAnimationResume(animator);
854         AnimatorCaller<ValueAnimator.AnimatorUpdateListener, ValueAnimator> ON_UPDATE =
855                 (listener, animator, isReverse) -> listener.onAnimationUpdate(animator);
856     }
857 }
858