Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5d23ef01 authored by Alan Viverette's avatar Alan Viverette Committed by Android (Google) Code Review
Browse files

Merge "Set AnimationDrawable running to false unless animation is scheduled"

parents 7659ce4e 70e68e0f
Loading
Loading
Loading
Loading
+47 −36
Original line number Diff line number Diff line
@@ -31,20 +31,23 @@ import android.os.SystemClock;
import android.util.AttributeSet;

/**
 * An object used to create frame-by-frame animations, defined by a series of Drawable objects,
 * which can be used as a View object's background.
 * An object used to create frame-by-frame animations, defined by a series of
 * Drawable objects, which can be used as a View object's background.
 * <p>
 * The simplest way to create a frame-by-frame animation is to define the animation in an XML
 * file, placed in the res/drawable/ folder, and set it as the background to a View object. Then, call
 * {@link #start()} to run the animation.
 * The simplest way to create a frame-by-frame animation is to define the
 * animation in an XML file, placed in the res/drawable/ folder, and set it as
 * the background to a View object. Then, call {@link #start()} to run the
 * animation.
 * <p>
 * An AnimationDrawable defined in XML consists of a single <code>&lt;animation-list></code> element,
 * and a series of nested <code>&lt;item></code> tags. Each item defines a frame of the animation.
 * See the example below.
 * </p>
 * <p>spin_animation.xml file in res/drawable/ folder:</p>
 * <pre>&lt;!-- Animation frames are wheel0.png -- wheel5.png files inside the
 * res/drawable/ folder --&gt;
 * An AnimationDrawable defined in XML consists of a single
 * {@code &lt;animation-list&gt;} element and a series of nested
 * {@code &lt;item&gt;} tags. Each item defines a frame of the animation. See
 * the example below.
 * <p>
 * spin_animation.xml file in res/drawable/ folder:
 * <pre>
 * &lt;!-- Animation frames are wheel0.png through wheel5.png
 *     files inside the res/drawable/ folder --&gt;
 * &lt;animation-list android:id=&quot;@+id/selected&quot; android:oneshot=&quot;false&quot;&gt;
 *    &lt;item android:drawable=&quot;@drawable/wheel0&quot; android:duration=&quot;50&quot; /&gt;
 *    &lt;item android:drawable=&quot;@drawable/wheel1&quot; android:duration=&quot;50&quot; /&gt;
@@ -53,8 +56,8 @@ import android.util.AttributeSet;
 *    &lt;item android:drawable=&quot;@drawable/wheel4&quot; android:duration=&quot;50&quot; /&gt;
 *    &lt;item android:drawable=&quot;@drawable/wheel5&quot; android:duration=&quot;50&quot; /&gt;
 * &lt;/animation-list&gt;</pre>
 *
 * <p>Here is the code to load and play this animation.</p>
 * <p>
 * Here is the code to load and play this animation.
 * <pre>
 * // Load the ImageView that will host the animation and
 * // set its background to our AnimationDrawable XML resource.
@@ -128,13 +131,17 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
    }

    /**
     * <p>Starts the animation, looping if necessary. This method has no effect
     * if the animation is running. Do not call this in the {@link android.app.Activity#onCreate}
     * method of your activity, because the {@link android.graphics.drawable.AnimationDrawable} is
     * not yet fully attached to the window. If you want to play
     * the animation immediately, without requiring interaction, then you might want to call it
     * from the {@link android.app.Activity#onWindowFocusChanged} method in your activity,
     * which will get called when Android brings your window into focus.</p>
     * Starts the animation, looping if necessary. This method has no effect
     * if the animation is running.
     * <p>
     * <strong>Note:</strong> Do not call this in the
     * {@link android.app.Activity#onCreate} method of your activity, because
     * the {@link AnimationDrawable} is not yet fully attached to the window.
     * If you want to play the animation immediately without requiring
     * interaction, then you might want to call it from the
     * {@link android.app.Activity#onWindowFocusChanged} method in your
     * activity, which will get called when Android brings your window into
     * focus.
     *
     * @see #isRunning()
     * @see #stop()
@@ -149,8 +156,8 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
    }

    /**
     * <p>Stops the animation. This method has no effect if the animation is
     * not running.</p>
     * Stops the animation. This method has no effect if the animation is not
     * running.
     *
     * @see #isRunning()
     * @see #start()
@@ -165,7 +172,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
    }

    /**
     * <p>Indicates whether the animation is currently running or not.</p>
     * Indicates whether the animation is currently running or not.
     *
     * @return true if the animation is running, false otherwise
     */
@@ -175,8 +182,8 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
    }

    /**
     * <p>This method exists for implementation purpose only and should not be
     * called directly. Invoke {@link #start()} instead.</p>
     * This method exists for implementation purpose only and should not be
     * called directly. Invoke {@link #start()} instead.
     *
     * @see #start()
     */
@@ -231,12 +238,12 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
    }

    /**
     * Add a frame to the animation
     * Adds a frame to the animation
     *
     * @param frame The frame to add
     * @param duration How long in milliseconds the frame should appear
     */
    public void addFrame(Drawable frame, int duration) {
    public void addFrame(@NonNull Drawable frame, int duration) {
        mAnimationState.addFrame(frame, duration);
        if (mCurFrame < 0) {
            setFrame(0, true, false);
@@ -244,13 +251,16 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
    }

    private void nextFrame(boolean unschedule) {
        int next = mCurFrame+1;
        final int N = mAnimationState.getChildCount();
        if (next >= N) {
            next = 0;
        int nextFrame = mCurFrame + 1;
        final int numFrames = mAnimationState.getChildCount();
        final boolean isLastFrame = mAnimationState.mOneShot && nextFrame >= (numFrames - 1);

        // Loop if necessary. One-shot animations should never hit this case.
        if (!mAnimationState.mOneShot && nextFrame >= numFrames) {
            nextFrame = 0;
        }

        setFrame(next, unschedule, !mAnimationState.mOneShot || next < (N - 1));
        setFrame(nextFrame, unschedule, !isLastFrame);
    }

    private void setFrame(int frame, boolean unschedule, boolean animate) {
@@ -262,6 +272,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
        selectDrawable(frame);
        if (unschedule || animate) {
            unscheduleSelf(this);
            mRunning = false;
        }
        if (animate) {
            // Unscheduling may have clobbered these values; restore them
@@ -341,6 +352,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
    }

    @Override
    @NonNull
    public Drawable mutate() {
        if (!mMutated && super.mutate() == this) {
            mAnimationState.mutate();
@@ -366,8 +378,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
        private int[] mDurations;
        private boolean mOneShot = false;

        AnimationState(AnimationState orig, AnimationDrawable owner,
                Resources res) {
        AnimationState(AnimationState orig, AnimationDrawable owner, Resources res) {
            super(orig, owner, res);

            if (orig != null) {