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