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 Original line Diff line number Diff line
@@ -31,20 +31,23 @@ import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.AttributeSet;


/**
/**
 * An object used to create frame-by-frame animations, defined by a series of Drawable objects,
 * An object used to create frame-by-frame animations, defined by a series of
 * which can be used as a View object's background.
 * Drawable objects, which can be used as a View object's background.
 * <p>
 * <p>
 * The simplest way to create a frame-by-frame animation is to define the animation in an XML
 * The simplest way to create a frame-by-frame animation is to define the
 * file, placed in the res/drawable/ folder, and set it as the background to a View object. Then, call
 * animation in an XML file, placed in the res/drawable/ folder, and set it as
 * {@link #start()} to run the animation.
 * the background to a View object. Then, call {@link #start()} to run the
 * animation.
 * <p>
 * <p>
 * An AnimationDrawable defined in XML consists of a single <code>&lt;animation-list></code> element,
 * An AnimationDrawable defined in XML consists of a single
 * and a series of nested <code>&lt;item></code> tags. Each item defines a frame of the animation.
 * {@code &lt;animation-list&gt;} element and a series of nested
 * See the example below.
 * {@code &lt;item&gt;} tags. Each item defines a frame of the animation. See
 * </p>
 * the example below.
 * <p>spin_animation.xml file in res/drawable/ folder:</p>
 * <p>
 * <pre>&lt;!-- Animation frames are wheel0.png -- wheel5.png files inside the
 * spin_animation.xml file in res/drawable/ folder:
 * res/drawable/ folder --&gt;
 * <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;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/wheel0&quot; android:duration=&quot;50&quot; /&gt;
 *    &lt;item android:drawable=&quot;@drawable/wheel1&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/wheel4&quot; android:duration=&quot;50&quot; /&gt;
 *    &lt;item android:drawable=&quot;@drawable/wheel5&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>
 * &lt;/animation-list&gt;</pre>
 *
 * <p>
 * <p>Here is the code to load and play this animation.</p>
 * Here is the code to load and play this animation.
 * <pre>
 * <pre>
 * // Load the ImageView that will host the animation and
 * // Load the ImageView that will host the animation and
 * // set its background to our AnimationDrawable XML resource.
 * // 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
     * 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}
     * if the animation is running.
     * method of your activity, because the {@link android.graphics.drawable.AnimationDrawable} is
     * <p>
     * not yet fully attached to the window. If you want to play
     * <strong>Note:</strong> Do not call this in the
     * the animation immediately, without requiring interaction, then you might want to call it
     * {@link android.app.Activity#onCreate} method of your activity, because
     * from the {@link android.app.Activity#onWindowFocusChanged} method in your activity,
     * the {@link AnimationDrawable} is not yet fully attached to the window.
     * which will get called when Android brings your window into focus.</p>
     * 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 #isRunning()
     * @see #stop()
     * @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
     * Stops the animation. This method has no effect if the animation is not
     * not running.</p>
     * running.
     *
     *
     * @see #isRunning()
     * @see #isRunning()
     * @see #start()
     * @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
     * @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
     * This method exists for implementation purpose only and should not be
     * called directly. Invoke {@link #start()} instead.</p>
     * called directly. Invoke {@link #start()} instead.
     *
     *
     * @see #start()
     * @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 frame The frame to add
     * @param duration How long in milliseconds the frame should appear
     * @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);
        mAnimationState.addFrame(frame, duration);
        if (mCurFrame < 0) {
        if (mCurFrame < 0) {
            setFrame(0, true, false);
            setFrame(0, true, false);
@@ -244,13 +251,16 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
    }
    }


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

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


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


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


            if (orig != null) {
            if (orig != null) {