19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.graphics.drawable;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.xmlpull.v1.XmlPullParser;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.xmlpull.v1.XmlPullParserException;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Resources;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.TypedArray;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * An object used to create frame-by-frame animations, defined by a series of Drawable objects,
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * which can be used as a View object's background.
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The simplest way to create a frame-by-frame animation is to define the animation in an XML
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * file, placed in the res/drawable/ folder, and set it as the background to a View object. Then, call
3634235c6eded32fa6840db7a0f38e0e2905aff8b0Scott Main * {@link #start()} to run the animation.
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * An AnimationDrawable defined in XML consists of a single <code>&lt;animation-list></code> element,
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and a series of nested <code>&lt;item></code> tags. Each item defines a frame of the animation.
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the example below.
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * </p>
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>spin_animation.xml file in res/drawable/ folder:</p>
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <pre>&lt;!-- Animation frames are wheel0.png -- wheel5.png files inside the
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * res/drawable/ folder --&gt;
45f7917e656b94ec2adfc3fa826e093665d39748d2Chet Haase * &lt;animation-list android:id=&quot;@+id/selected&quot; android:oneshot=&quot;false&quot;&gt;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *    &lt;item android:drawable=&quot;@drawable/wheel0&quot; android:duration=&quot;50&quot; /&gt;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *    &lt;item android:drawable=&quot;@drawable/wheel1&quot; android:duration=&quot;50&quot; /&gt;
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *    &lt;item android:drawable=&quot;@drawable/wheel2&quot; android:duration=&quot;50&quot; /&gt;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *    &lt;item android:drawable=&quot;@drawable/wheel3&quot; android:duration=&quot;50&quot; /&gt;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *    &lt;item android:drawable=&quot;@drawable/wheel4&quot; android:duration=&quot;50&quot; /&gt;
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *    &lt;item android:drawable=&quot;@drawable/wheel5&quot; android:duration=&quot;50&quot; /&gt;
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * &lt;/animation-list&gt;</pre>
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>Here is the code to load and play this animation.</p>
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <pre>
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * // Load the ImageView that will host the animation and
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * // set its background to our AnimationDrawable XML resource.
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * ImageView img = (ImageView)findViewById(R.id.spinning_wheel_image);
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * img.setBackgroundResource(R.drawable.spin_animation);
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * // Get the background, which has been compiled to an AnimationDrawable object.
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * AnimationDrawable frameAnimation = (AnimationDrawable) img.getBackground();
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * // Start the animation (looped playback by default).
65f5534a0785db9dfa239d8b6c20b011993742d534Chet Haase * frameAnimation.start();
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * </pre>
673aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez *
683aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <div class="special reference">
693aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <h3>Developer Guides</h3>
703aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <p>For more information about animating with {@code AnimationDrawable}, read the
713aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <a href="{@docRoot}guide/topics/graphics/drawable-animation.html">Drawable Animation</a>
723aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * developer guide.</p>
733aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * </div>
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#AnimationDrawable_visible
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#AnimationDrawable_variablePadding
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#AnimationDrawable_oneshot
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#AnimationDrawableItem_duration
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#AnimationDrawableItem_drawable
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
81b5537c452271634b6ff3981b0624fa65384abd5bRomain Guypublic class AnimationDrawable extends DrawableContainer implements Runnable, Animatable {
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final AnimationState mAnimationState;
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mCurFrame = -1;
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mMutated;
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public AnimationDrawable() {
87c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        this(null, null);
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean setVisible(boolean visible, boolean restart) {
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean changed = super.setVisible(visible, restart);
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (visible) {
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (changed || restart) {
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                setFrame(0, true, true);
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            unscheduleSelf(this);
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return changed;
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>Starts the animation, looping if necessary. This method has no effect
1059366ce81dbaa1c954911ef1c8d5791bb4a69d89cRobert Ly     * if the animation is running. Do not call this in the {@link android.app.Activity#onCreate}
1069366ce81dbaa1c954911ef1c8d5791bb4a69d89cRobert Ly     * method of your activity, because the {@link android.graphics.drawable.AnimationDrawable} is
1079366ce81dbaa1c954911ef1c8d5791bb4a69d89cRobert Ly     * not yet fully attached to the window. If you want to play
1089366ce81dbaa1c954911ef1c8d5791bb4a69d89cRobert Ly     * the animation immediately, without requiring interaction, then you might want to call it
1099366ce81dbaa1c954911ef1c8d5791bb4a69d89cRobert Ly     * from the {@link android.app.Activity#onWindowFocusChanged} method in your activity,
1109366ce81dbaa1c954911ef1c8d5791bb4a69d89cRobert Ly     * which will get called when Android brings your window into focus.</p>
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #isRunning()
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #stop()
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void start() {
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!isRunning()) {
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            run();
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>Stops the animation. This method has no effect if the animation is
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * not running.</p>
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #isRunning()
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #start()
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void stop() {
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (isRunning()) {
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            unscheduleSelf(this);
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>Indicates whether the animation is currently running or not.</p>
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return true if the animation is running, false otherwise
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isRunning() {
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mCurFrame > -1;
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>This method exists for implementation purpose only and should not be
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * called directly. Invoke {@link #start()} instead.</p>
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #start()
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void run() {
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        nextFrame(false);
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void unscheduleSelf(Runnable what) {
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCurFrame = -1;
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.unscheduleSelf(what);
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The number of frames in the animation
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getNumberOfFrames() {
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mAnimationState.getChildCount();
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The Drawable at the specified frame index
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Drawable getFrame(int index) {
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mAnimationState.getChildren()[index];
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The duration in milliseconds of the frame at the
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * specified index
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getDuration(int i) {
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mAnimationState.mDurations[i];
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return True of the animation will play once, false otherwise
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isOneShot() {
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mAnimationState.mOneShot;
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets whether the animation should play once or repeat.
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param oneShot Pass true if the animation should only play once
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setOneShot(boolean oneShot) {
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAnimationState.mOneShot = oneShot;
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Add a frame to the animation
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param frame The frame to add
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param duration How long in milliseconds the frame should appear
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void addFrame(Drawable frame, int duration) {
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAnimationState.addFrame(frame, duration);
205f5534a0785db9dfa239d8b6c20b011993742d534Chet Haase        if (mCurFrame < 0) {
206f5534a0785db9dfa239d8b6c20b011993742d534Chet Haase            setFrame(0, true, false);
207f5534a0785db9dfa239d8b6c20b011993742d534Chet Haase        }
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void nextFrame(boolean unschedule) {
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int next = mCurFrame+1;
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int N = mAnimationState.getChildCount();
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (next >= N) {
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            next = 0;
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setFrame(next, unschedule, !mAnimationState.mOneShot || next < (N - 1));
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void setFrame(int frame, boolean unschedule, boolean animate) {
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (frame >= mAnimationState.getChildCount()) {
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCurFrame = frame;
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        selectDrawable(frame);
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (unschedule) {
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            unscheduleSelf(this);
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (animate) {
229f7917e656b94ec2adfc3fa826e093665d39748d2Chet Haase            // Unscheduling may have clobbered this value; restore it to record that we're animating
230f7917e656b94ec2adfc3fa826e093665d39748d2Chet Haase            mCurFrame = frame;
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            scheduleSelf(this, SystemClock.uptimeMillis() + mAnimationState.mDurations[frame]);
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws XmlPullParserException, IOException {
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        TypedArray a = r.obtainAttributes(attrs,
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                com.android.internal.R.styleable.AnimationDrawable);
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.inflateWithAttributes(r, parser, a,
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                com.android.internal.R.styleable.AnimationDrawable_visible);
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAnimationState.setVariablePadding(a.getBoolean(
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                com.android.internal.R.styleable.AnimationDrawable_variablePadding, false));
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAnimationState.mOneShot = a.getBoolean(
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                com.android.internal.R.styleable.AnimationDrawable_oneshot, false);
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        a.recycle();
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int type;
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int innerDepth = parser.getDepth()+1;
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int depth;
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT &&
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (type != XmlPullParser.START_TAG) {
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                continue;
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (depth > innerDepth || !parser.getName().equals("item")) {
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                continue;
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            a = r.obtainAttributes(attrs, com.android.internal.R.styleable.AnimationDrawableItem);
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int duration = a.getInt(
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    com.android.internal.R.styleable.AnimationDrawableItem_duration, -1);
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (duration < 0) {
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new XmlPullParserException(
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        parser.getPositionDescription()
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + ": <item> tag requires a 'duration' attribute");
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int drawableRes = a.getResourceId(
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    com.android.internal.R.styleable.AnimationDrawableItem_drawable, 0);
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            a.recycle();
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Drawable dr;
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (drawableRes != 0) {
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                dr = r.getDrawable(drawableRes);
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                while ((type=parser.next()) == XmlPullParser.TEXT) {
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Empty
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (type != XmlPullParser.START_TAG) {
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    throw new XmlPullParserException(parser.getPositionDescription() +
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            ": <item> tag requires a 'drawable' attribute or child tag" +
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            " defining a drawable");
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                dr = Drawable.createFromXmlInner(r, parser, attrs);
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAnimationState.addFrame(dr, duration);
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (dr != null) {
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                dr.setCallback(this);
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setFrame(0, true, false);
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Drawable mutate() {
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mMutated && super.mutate() == this) {
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAnimationState.mDurations = mAnimationState.mDurations.clone();
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMutated = true;
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return this;
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final static class AnimationState extends DrawableContainerState {
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int[] mDurations;
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private boolean mOneShot;
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
317c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        AnimationState(AnimationState orig, AnimationDrawable owner,
318c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn                Resources res) {
319c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn            super(orig, owner, res);
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (orig != null) {
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mDurations = orig.mDurations;
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mOneShot = orig.mOneShot;
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mDurations = new int[getChildren().length];
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mOneShot = true;
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Drawable newDrawable() {
332c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn            return new AnimationDrawable(this, null);
333c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        }
334c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn
335c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        @Override
336c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        public Drawable newDrawable(Resources res) {
337c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn            return new AnimationDrawable(this, res);
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void addFrame(Drawable dr, int dur) {
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Do not combine the following. The array index must be evaluated before
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // the array is accessed because super.addChild(dr) has a side effect on mDurations.
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int pos = super.addChild(dr);
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDurations[pos] = dur;
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void growArray(int oldSize, int newSize) {
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super.growArray(oldSize, newSize);
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int[] newDurations = new int[newSize];
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            System.arraycopy(mDurations, 0, newDurations, 0, oldSize);
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDurations = newDurations;
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
356c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    private AnimationDrawable(AnimationState state, Resources res) {
357c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        AnimationState as = new AnimationState(state, this, res);
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAnimationState = as;
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setConstantState(as);
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (state != null) {
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setFrame(0, true, false);
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
366