auto import from //depot/cupcake/@135843
This commit is contained in:
@@ -1,342 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.graphics.drawable;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
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.
|
||||
* <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 #run()} to start the animation.
|
||||
* <p>
|
||||
* An AnimationDrawable defined in XML consists of a single <code><animation-list></code> element,
|
||||
* and a series of nested <code><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><!-- Animation frames are wheel0.png -- wheel5.png files inside the
|
||||
* res/drawable/ folder -->
|
||||
* <animation-list android:id="selected" android:oneshot="false">
|
||||
* <item android:drawable="@drawable/wheel0" android:duration="50" />
|
||||
* <item android:drawable="@drawable/wheel1" android:duration="50" />
|
||||
* <item android:drawable="@drawable/wheel2" android:duration="50" />
|
||||
* <item android:drawable="@drawable/wheel3" android:duration="50" />
|
||||
* <item android:drawable="@drawable/wheel4" android:duration="50" />
|
||||
* <item android:drawable="@drawable/wheel5" android:duration="50" />
|
||||
* </animation-list></pre>
|
||||
*
|
||||
* <p>Here is the code to load and play this animation.</p>
|
||||
* <pre>
|
||||
* // Load the ImageView that will host the animation and
|
||||
* // set its background to our AnimationDrawable XML resource.
|
||||
* ImageView img = (ImageView)findViewById(R.id.spinning_wheel_image);
|
||||
* img.setBackgroundResource(R.drawable.spin_animation);
|
||||
*
|
||||
* // Get the background, which has been compiled to an AnimationDrawable object.
|
||||
* AnimationDrawable frameAnimation = (AnimationDrawable) img.getBackground();
|
||||
*
|
||||
* // Start the animation (looped playback by default).
|
||||
* frameAnimation.start()
|
||||
* </pre>
|
||||
*
|
||||
* @attr ref android.R.styleable#AnimationDrawable_visible
|
||||
* @attr ref android.R.styleable#AnimationDrawable_variablePadding
|
||||
* @attr ref android.R.styleable#AnimationDrawable_oneshot
|
||||
* @attr ref android.R.styleable#AnimationDrawableItem_duration
|
||||
* @attr ref android.R.styleable#AnimationDrawableItem_drawable
|
||||
*/
|
||||
public class AnimationDrawable extends DrawableContainer implements Runnable {
|
||||
private final AnimationState mAnimationState;
|
||||
private int mCurFrame = -1;
|
||||
private boolean mMutated;
|
||||
|
||||
public AnimationDrawable() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setVisible(boolean visible, boolean restart) {
|
||||
boolean changed = super.setVisible(visible, restart);
|
||||
if (visible) {
|
||||
if (changed || restart) {
|
||||
setFrame(0, true, true);
|
||||
}
|
||||
} else {
|
||||
unscheduleSelf(this);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Starts the animation, looping if necessary. This method has no effect
|
||||
* if the animation is running.</p>
|
||||
*
|
||||
* @see #isRunning()
|
||||
* @see #stop()
|
||||
*/
|
||||
public void start() {
|
||||
if (!isRunning()) {
|
||||
run();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Stops the animation. This method has no effect if the animation is
|
||||
* not running.</p>
|
||||
*
|
||||
* @see #isRunning()
|
||||
* @see #start()
|
||||
*/
|
||||
public void stop() {
|
||||
if (isRunning()) {
|
||||
unscheduleSelf(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Indicates whether the animation is currently running or not.</p>
|
||||
*
|
||||
* @return true if the animation is running, false otherwise
|
||||
*/
|
||||
public boolean isRunning() {
|
||||
return mCurFrame > -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>This method exists for implementation purpose only and should not be
|
||||
* called directly. Invoke {@link #start()} instead.</p>
|
||||
*
|
||||
* @see #start()
|
||||
*/
|
||||
public void run() {
|
||||
nextFrame(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unscheduleSelf(Runnable what) {
|
||||
mCurFrame = -1;
|
||||
super.unscheduleSelf(what);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of frames in the animation
|
||||
*/
|
||||
public int getNumberOfFrames() {
|
||||
return mAnimationState.getChildCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The Drawable at the specified frame index
|
||||
*/
|
||||
public Drawable getFrame(int index) {
|
||||
return mAnimationState.getChildren()[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The duration in milliseconds of the frame at the
|
||||
* specified index
|
||||
*/
|
||||
public int getDuration(int i) {
|
||||
return mAnimationState.mDurations[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True of the animation will play once, false otherwise
|
||||
*/
|
||||
public boolean isOneShot() {
|
||||
return mAnimationState.mOneShot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the animation should play once or repeat.
|
||||
*
|
||||
* @param oneShot Pass true if the animation should only play once
|
||||
*/
|
||||
public void setOneShot(boolean oneShot) {
|
||||
mAnimationState.mOneShot = oneShot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add 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) {
|
||||
mAnimationState.addFrame(frame, duration);
|
||||
}
|
||||
|
||||
private void nextFrame(boolean unschedule) {
|
||||
int next = mCurFrame+1;
|
||||
final int N = mAnimationState.getChildCount();
|
||||
if (next >= N) {
|
||||
next = 0;
|
||||
}
|
||||
setFrame(next, unschedule, !mAnimationState.mOneShot || next < (N - 1));
|
||||
}
|
||||
|
||||
private void setFrame(int frame, boolean unschedule, boolean animate) {
|
||||
if (frame >= mAnimationState.getChildCount()) {
|
||||
return;
|
||||
}
|
||||
mCurFrame = frame;
|
||||
selectDrawable(frame);
|
||||
if (unschedule) {
|
||||
unscheduleSelf(this);
|
||||
}
|
||||
if (animate) {
|
||||
scheduleSelf(this, SystemClock.uptimeMillis() + mAnimationState.mDurations[frame]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
|
||||
throws XmlPullParserException, IOException {
|
||||
|
||||
TypedArray a = r.obtainAttributes(attrs,
|
||||
com.android.internal.R.styleable.AnimationDrawable);
|
||||
|
||||
super.inflateWithAttributes(r, parser, a,
|
||||
com.android.internal.R.styleable.AnimationDrawable_visible);
|
||||
|
||||
mAnimationState.setVariablePadding(a.getBoolean(
|
||||
com.android.internal.R.styleable.AnimationDrawable_variablePadding, false));
|
||||
|
||||
mAnimationState.mOneShot = a.getBoolean(
|
||||
com.android.internal.R.styleable.AnimationDrawable_oneshot, false);
|
||||
|
||||
a.recycle();
|
||||
|
||||
int type;
|
||||
|
||||
final int innerDepth = parser.getDepth()+1;
|
||||
int depth;
|
||||
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT &&
|
||||
((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
|
||||
if (type != XmlPullParser.START_TAG) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (depth > innerDepth || !parser.getName().equals("item")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
a = r.obtainAttributes(attrs, com.android.internal.R.styleable.AnimationDrawableItem);
|
||||
int duration = a.getInt(
|
||||
com.android.internal.R.styleable.AnimationDrawableItem_duration, -1);
|
||||
if (duration < 0) {
|
||||
throw new XmlPullParserException(
|
||||
parser.getPositionDescription()
|
||||
+ ": <item> tag requires a 'duration' attribute");
|
||||
}
|
||||
int drawableRes = a.getResourceId(
|
||||
com.android.internal.R.styleable.AnimationDrawableItem_drawable, 0);
|
||||
|
||||
a.recycle();
|
||||
|
||||
Drawable dr;
|
||||
if (drawableRes != 0) {
|
||||
dr = r.getDrawable(drawableRes);
|
||||
} else {
|
||||
while ((type=parser.next()) == XmlPullParser.TEXT) {
|
||||
// Empty
|
||||
}
|
||||
if (type != XmlPullParser.START_TAG) {
|
||||
throw new XmlPullParserException(parser.getPositionDescription() +
|
||||
": <item> tag requires a 'drawable' attribute or child tag" +
|
||||
" defining a drawable");
|
||||
}
|
||||
dr = Drawable.createFromXmlInner(r, parser, attrs);
|
||||
}
|
||||
|
||||
mAnimationState.addFrame(dr, duration);
|
||||
if (dr != null) {
|
||||
dr.setCallback(this);
|
||||
}
|
||||
}
|
||||
|
||||
setFrame(0, true, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable mutate() {
|
||||
if (!mMutated && super.mutate() == this) {
|
||||
mAnimationState.mDurations = mAnimationState.mDurations.clone();
|
||||
mMutated = true;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private final static class AnimationState extends DrawableContainerState {
|
||||
private int[] mDurations;
|
||||
private boolean mOneShot;
|
||||
|
||||
AnimationState(AnimationState orig, AnimationDrawable owner) {
|
||||
super(orig, owner);
|
||||
|
||||
if (orig != null) {
|
||||
mDurations = orig.mDurations;
|
||||
mOneShot = orig.mOneShot;
|
||||
} else {
|
||||
mDurations = new int[getChildren().length];
|
||||
mOneShot = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable newDrawable() {
|
||||
return new AnimationDrawable(this);
|
||||
}
|
||||
|
||||
public void addFrame(Drawable dr, int dur) {
|
||||
// Do not combine the following. The array index must be evaluated before
|
||||
// the array is accessed because super.addChild(dr) has a side effect on mDurations.
|
||||
int pos = super.addChild(dr);
|
||||
mDurations[pos] = dur;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void growArray(int oldSize, int newSize) {
|
||||
super.growArray(oldSize, newSize);
|
||||
int[] newDurations = new int[newSize];
|
||||
System.arraycopy(mDurations, 0, newDurations, 0, oldSize);
|
||||
mDurations = newDurations;
|
||||
}
|
||||
}
|
||||
|
||||
private AnimationDrawable(AnimationState state) {
|
||||
AnimationState as = new AnimationState(state, this);
|
||||
mAnimationState = as;
|
||||
setConstantState(as);
|
||||
if (state != null) {
|
||||
setFrame(0, true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user