Add add/remove for AnimationListener's

FragmentManagerImpl in AndroidX currently uses reflection to read
mListener, so it can wrap it with another listener. Adding add/remove
methods for AnimationListener's next to setAnimationListener removes the
need for AndroidX to touch mListener, which is private API.

Bug: 117519981
Test: atest AnimationTest
Change-Id: I69cb19d61078215ca6697b3d41f4c536decc2e6e
This commit is contained in:
Jelle Fresen
2018-11-30 10:23:25 +00:00
parent d5ad1252a3
commit 65d2171d00
3 changed files with 86 additions and 24 deletions

View File

@@ -51899,6 +51899,7 @@ package android.view.animation {
public abstract class Animation implements java.lang.Cloneable {
ctor public Animation();
ctor public Animation(android.content.Context, android.util.AttributeSet);
method public void addAnimationListener(android.view.animation.Animation.AnimationListener);
method protected void applyTransformation(float, android.view.animation.Transformation);
method public void cancel();
method protected android.view.animation.Animation clone() throws java.lang.CloneNotSupportedException;
@@ -51923,6 +51924,7 @@ package android.view.animation {
method public void initialize(int, int, int, int);
method public boolean isFillEnabled();
method public boolean isInitialized();
method public void removeAnimationListener(android.view.animation.Animation.AnimationListener);
method public void reset();
method protected float resolveSize(int, float, int, int);
method public void restrictDuration(long);

View File

@@ -30,6 +30,9 @@ import android.util.TypedValue;
import dalvik.system.CloseGuard;
import java.util.ArrayList;
import java.util.List;
/**
* Abstraction for an Animation that can be applied to Views, Surfaces, or
* other objects. See the {@link android.view.animation animation package
@@ -182,10 +185,14 @@ public abstract class Animation implements Cloneable {
Interpolator mInterpolator;
/**
* The animation listener to be notified when the animation starts, ends or repeats.
* An animation listener to be notified when the animation starts, ends or repeats.
*/
@UnsupportedAppUsage
AnimationListener mListener;
private AnimationListener mListener;
/**
* A list of animation listeners to be notified when the animation starts, ends or repeats.
*/
private List<AnimationListener> mListeners;
/**
* Desired Z order mode during animation.
@@ -371,23 +378,17 @@ public abstract class Animation implements Cloneable {
if (mListenerHandler == null) {
mOnStart = new Runnable() {
public void run() {
if (mListener != null) {
mListener.onAnimationStart(Animation.this);
}
dispatchAnimationStart();
}
};
mOnRepeat = new Runnable() {
public void run() {
if (mListener != null) {
mListener.onAnimationRepeat(Animation.this);
}
dispatchAnimationRepeat();
}
};
mOnEnd = new Runnable() {
public void run() {
if (mListener != null) {
mListener.onAnimationEnd(Animation.this);
}
dispatchAnimationEnd();
}
};
}
@@ -830,6 +831,10 @@ public abstract class Animation implements Cloneable {
return true;
}
private boolean hasAnimationListener() {
return mListener != null || (mListeners != null && !mListeners.isEmpty());
}
/**
* <p>Binds an animation listener to this animation. The animation listener
* is notified of animation events such as the end of the animation or the
@@ -841,6 +846,32 @@ public abstract class Animation implements Cloneable {
mListener = listener;
}
/**
* <p>Adds an animation listener to this animation. The animation listener
* is notified of animation events such as the end of the animation or the
* repetition of the animation.</p>
*
* @param listener the animation listener to be notified
*/
public void addAnimationListener(AnimationListener listener) {
if (mListeners == null) {
mListeners = new ArrayList<>(1);
}
mListeners.add(listener);
}
/**
* <p>Removes an animation listener that has been added with
* {@link #addAnimationListener(AnimationListener)}.</p>
*
* @param listener the animation listener to be removed
*/
public void removeAnimationListener(AnimationListener listener) {
if (mListeners != null) {
mListeners.remove(listener);
}
}
/**
* Gurantees that this animation has an interpolator. Will use
* a AccelerateDecelerateInterpolator is nothing else was specified.
@@ -947,26 +978,59 @@ public abstract class Animation implements Cloneable {
}
private void fireAnimationStart() {
if (mListener != null) {
if (mListenerHandler == null) mListener.onAnimationStart(this);
if (hasAnimationListener()) {
if (mListenerHandler == null) dispatchAnimationStart();
else mListenerHandler.postAtFrontOfQueue(mOnStart);
}
}
private void fireAnimationRepeat() {
if (mListener != null) {
if (mListenerHandler == null) mListener.onAnimationRepeat(this);
if (hasAnimationListener()) {
if (mListenerHandler == null) dispatchAnimationRepeat();
else mListenerHandler.postAtFrontOfQueue(mOnRepeat);
}
}
private void fireAnimationEnd() {
if (mListener != null) {
if (mListenerHandler == null) mListener.onAnimationEnd(this);
if (hasAnimationListener()) {
if (mListenerHandler == null) dispatchAnimationEnd();
else mListenerHandler.postAtFrontOfQueue(mOnEnd);
}
}
void dispatchAnimationStart() {
if (mListener != null) {
mListener.onAnimationStart(this);
}
if (mListeners != null && !mListeners.isEmpty()) {
for (AnimationListener listener : mListeners) {
listener.onAnimationStart(this);
}
}
}
void dispatchAnimationRepeat() {
if (mListener != null) {
mListener.onAnimationRepeat(this);
}
if (mListeners != null && !mListeners.isEmpty()) {
for (AnimationListener listener : mListeners) {
listener.onAnimationRepeat(this);
}
}
}
void dispatchAnimationEnd() {
if (mListener != null) {
mListener.onAnimationEnd(this);
}
if (mListeners != null && !mListeners.isEmpty()) {
for (AnimationListener listener : mListeners) {
listener.onAnimationEnd(this);
}
}
}
/**
* Gets the transformation to apply at a specified point in time. Implementations of this
* method should always replace the specified Transformation or document they are doing

View File

@@ -389,16 +389,12 @@ public class AnimationSet extends Animation {
}
if (started && !mStarted) {
if (mListener != null) {
mListener.onAnimationStart(this);
}
dispatchAnimationStart();
mStarted = true;
}
if (ended != mEnded) {
if (mListener != null) {
mListener.onAnimationEnd(this);
}
dispatchAnimationEnd();
mEnded = ended;
}