summaryrefslogtreecommitdiffstats
path: root/graphics/java
diff options
context:
space:
mode:
authorJean-Baptiste Queru <jbq@google.com>2009-07-21 11:16:54 -0700
committerJean-Baptiste Queru <jbq@google.com>2009-07-21 11:16:54 -0700
commitcf4550c3198d6b3d92cdc52707fe70d7cc0caa9f (patch)
tree6510f35ad004f1a4640b48264c290926e8596d7a /graphics/java
parent4cf03d381b2dff908857fceff0bec445f8d44f36 (diff)
downloadframeworks_base-cf4550c3198d6b3d92cdc52707fe70d7cc0caa9f.zip
frameworks_base-cf4550c3198d6b3d92cdc52707fe70d7cc0caa9f.tar.gz
frameworks_base-cf4550c3198d6b3d92cdc52707fe70d7cc0caa9f.tar.bz2
donut snapshot
Diffstat (limited to 'graphics/java')
-rw-r--r--graphics/java/android/graphics/Bitmap.java106
-rw-r--r--graphics/java/android/graphics/BitmapFactory.java44
-rw-r--r--graphics/java/android/graphics/Canvas.java6
-rw-r--r--graphics/java/android/graphics/NinePatch.java5
-rw-r--r--graphics/java/android/graphics/drawable/Animatable.java39
-rw-r--r--graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java332
-rw-r--r--graphics/java/android/graphics/drawable/AnimationDrawable.java2
-rw-r--r--graphics/java/android/graphics/drawable/Drawable.java2
-rw-r--r--graphics/java/android/graphics/drawable/DrawableContainer.java6
-rw-r--r--graphics/java/android/graphics/drawable/GradientDrawable.java4
10 files changed, 471 insertions, 75 deletions
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index fda584d..e2e93eb 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -16,14 +16,14 @@
package android.graphics;
-import android.os.Parcelable;
import android.os.Parcel;
+import android.os.Parcelable;
+import java.io.OutputStream;
import java.nio.Buffer;
import java.nio.ByteBuffer;
-import java.nio.ShortBuffer;
import java.nio.IntBuffer;
-import java.io.OutputStream;
+import java.nio.ShortBuffer;
public final class Bitmap implements Parcelable {
/**
@@ -32,14 +32,14 @@ public final class Bitmap implements Parcelable {
* @see Bitmap#getDensityScale()
* @see Bitmap#setDensityScale(float)
*
- * @hide pending API council approval
+ * @hide pending API council approval
*/
public static final float DENSITY_SCALE_UNKNOWN = -1.0f;
// Note: mNativeBitmap is used by FaceDetector_jni.cpp
// Don't change/rename without updating FaceDetector_jni.cpp
private final int mNativeBitmap;
-
+
private final boolean mIsMutable;
private byte[] mNinePatchChunk; // may be null
private int mWidth = -1;
@@ -63,7 +63,7 @@ public final class Bitmap implements Parcelable {
if (nativeBitmap == 0) {
throw new RuntimeException("internal error: native bitmap is 0");
}
-
+
// we delete this in our finalizer
mNativeBitmap = nativeBitmap;
mIsMutable = isMutable;
@@ -83,7 +83,7 @@ public final class Bitmap implements Parcelable {
*
* @see #setDensityScale(float)
* @see #isAutoScalingEnabled()
- * @see #setAutoScalingEnabled(boolean)
+ * @see #setAutoScalingEnabled(boolean)
* @see android.util.DisplayMetrics#DEFAULT_DENSITY
* @see android.util.DisplayMetrics#density
* @see #DENSITY_SCALE_UNKNOWN
@@ -105,7 +105,7 @@ public final class Bitmap implements Parcelable {
*
* @see #getDensityScale()
* @see #isAutoScalingEnabled()
- * @see #setAutoScalingEnabled(boolean)
+ * @see #setAutoScalingEnabled(boolean)
* @see android.util.DisplayMetrics#DEFAULT_DENSITY
* @see android.util.DisplayMetrics#density
* @see #DENSITY_SCALE_UNKNOWN
@@ -126,7 +126,7 @@ public final class Bitmap implements Parcelable {
* <p>Auto scaling is turned off by default. If auto scaling is enabled but the
* bitmap has an unknown density scale, then the bitmap will never be automatically
* scaled at drawing time.</p>
- *
+ *
* @return True if the bitmap must be scaled at drawing time, false otherwise.
*
* @see #setAutoScalingEnabled(boolean)
@@ -167,7 +167,7 @@ public final class Bitmap implements Parcelable {
public void setNinePatchChunk(byte[] chunk) {
mNinePatchChunk = chunk;
}
-
+
/**
* Free up the memory associated with this bitmap's pixels, and mark the
* bitmap as "dead", meaning it will throw an exception if getPixels() or
@@ -194,7 +194,7 @@ public final class Bitmap implements Parcelable {
public final boolean isRecycled() {
return mRecycled;
}
-
+
/**
* This is called by methods that want to throw an exception if the bitmap
* has already been recycled.
@@ -204,7 +204,7 @@ public final class Bitmap implements Parcelable {
throw new IllegalStateException(errorMessage);
}
}
-
+
/**
* Common code for checking that x and y are >= 0
*
@@ -246,16 +246,16 @@ public final class Bitmap implements Parcelable {
this.nativeInt = ni;
}
final int nativeInt;
-
+
/* package */ static Config nativeToConfig(int ni) {
return sConfigs[ni];
}
-
+
private static Config sConfigs[] = {
null, null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888
};
}
-
+
/**
* Copy the bitmap's pixels into the specified buffer (allocated by the
* caller). An exception is thrown if the buffer is not large enough to
@@ -275,16 +275,16 @@ public final class Bitmap implements Parcelable {
} else {
throw new RuntimeException("unsupported Buffer subclass");
}
-
+
long bufferSize = (long)elements << shift;
long pixelSize = (long)getRowBytes() * getHeight();
-
+
if (bufferSize < pixelSize) {
throw new RuntimeException("Buffer not large enough for pixels");
}
-
+
nativeCopyPixelsToBuffer(mNativeBitmap, dst);
-
+
// now update the buffer's position
int position = dst.position();
position += pixelSize >> shift;
@@ -299,7 +299,7 @@ public final class Bitmap implements Parcelable {
*/
public void copyPixelsFromBuffer(Buffer src) {
checkRecycled("copyPixelsFromBuffer called on recycled bitmap");
-
+
int elements = src.remaining();
int shift;
if (src instanceof ByteBuffer) {
@@ -311,17 +311,17 @@ public final class Bitmap implements Parcelable {
} else {
throw new RuntimeException("unsupported Buffer subclass");
}
-
+
long bufferBytes = (long)elements << shift;
long bitmapBytes = (long)getRowBytes() * getHeight();
-
+
if (bufferBytes < bitmapBytes) {
throw new RuntimeException("Buffer not large enough for pixels");
}
-
+
nativeCopyPixelsFromBuffer(mNativeBitmap, src);
}
-
+
/**
* Tries to make a new bitmap based on the dimensions of this bitmap,
* setting the new bitmap's config to the one specified, and then copying
@@ -350,7 +350,7 @@ public final class Bitmap implements Parcelable {
if (m == null) {
m = new Matrix();
}
-
+
final int width = src.getWidth();
final int height = src.getHeight();
final float sx = dstWidth / (float)width;
@@ -365,9 +365,9 @@ public final class Bitmap implements Parcelable {
}
}
- return b;
+ return b;
}
-
+
/**
* Returns an immutable bitmap from the source bitmap. The new bitmap may
* be the same object as source, or a copy may have been made.
@@ -390,7 +390,7 @@ public final class Bitmap implements Parcelable {
public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height) {
return createBitmap(source, x, y, width, height, null, false);
}
-
+
/**
* Returns an immutable bitmap from subset of the source bitmap,
* transformed by the optional matrix.
@@ -425,7 +425,7 @@ public final class Bitmap implements Parcelable {
height == source.getHeight() && (m == null || m.isIdentity())) {
return source;
}
-
+
int neww = width;
int newh = height;
Canvas canvas = new Canvas();
@@ -470,7 +470,7 @@ public final class Bitmap implements Parcelable {
return bitmap;
}
-
+
/**
* Returns a mutable bitmap with the specified width and height.
*
@@ -484,7 +484,7 @@ public final class Bitmap implements Parcelable {
bm.eraseColor(0); // start with black/transparent pixels
return bm;
}
-
+
/**
* Returns a immutable bitmap with the specified width and height, with each
* pixel value set to the corresponding value in the colors array.
@@ -593,7 +593,7 @@ public final class Bitmap implements Parcelable {
return nativeCompress(mNativeBitmap, format.nativeInt, quality,
stream, new byte[WORKING_COMPRESS_STORAGE]);
}
-
+
/**
* Returns true if the bitmap is marked as mutable (i.e. can be drawn into)
*/
@@ -610,7 +610,7 @@ public final class Bitmap implements Parcelable {
public final int getHeight() {
return mHeight == -1 ? mHeight = nativeHeight(mNativeBitmap) : mHeight;
}
-
+
/**
* Convenience method that returns the width of this bitmap divided
* by the density scale factor.
@@ -648,7 +648,7 @@ public final class Bitmap implements Parcelable {
public final int getRowBytes() {
return nativeRowBytes(mNativeBitmap);
}
-
+
/**
* If the bitmap's internal config is in one of the public formats, return
* that config, otherwise return null.
@@ -690,7 +690,7 @@ public final class Bitmap implements Parcelable {
checkPixelAccess(x, y);
return nativeGetPixel(mNativeBitmap, x, y);
}
-
+
/**
* Returns in pixels[] a copy of the data in the bitmap. Each value is
* a packed int representing a {@link Color}. The stride parameter allows
@@ -722,7 +722,7 @@ public final class Bitmap implements Parcelable {
nativeGetPixels(mNativeBitmap, pixels, offset, stride,
x, y, width, height);
}
-
+
/**
* Shared code to check for illegal arguments passed to getPixel()
* or setPixel()
@@ -779,7 +779,7 @@ public final class Bitmap implements Parcelable {
throw new ArrayIndexOutOfBoundsException();
}
}
-
+
/**
* Write the specified {@link Color} into the bitmap (assuming it is
* mutable) at the x,y coordinate.
@@ -799,10 +799,10 @@ public final class Bitmap implements Parcelable {
checkPixelAccess(x, y);
nativeSetPixel(mNativeBitmap, x, y, color);
}
-
+
/**
* Replace pixels in the bitmap with the colors in the array. Each element
- * in the array is a packed int prepresenting a {@link Color}
+ * in the array is a packed int prepresenting a {@link Color}
*
* @param pixels The colors to write to the bitmap
* @param offset The index of the first color to read from pixels[]
@@ -834,7 +834,7 @@ public final class Bitmap implements Parcelable {
nativeSetPixels(mNativeBitmap, pixels, offset, stride,
x, y, width, height);
}
-
+
public static final Parcelable.Creator<Bitmap> CREATOR
= new Parcelable.Creator<Bitmap>() {
/**
@@ -884,7 +884,7 @@ public final class Bitmap implements Parcelable {
public Bitmap extractAlpha() {
return extractAlpha(null, null);
}
-
+
/**
* Returns a new bitmap that captures the alpha values of the original.
* These values may be affected by the optional Paint parameter, which
@@ -917,6 +917,22 @@ public final class Bitmap implements Parcelable {
return bm;
}
+ /**
+ * Rebuilds any caches associated with the bitmap that are used for
+ * drawing it. In the case of purgeable bitmaps, this call will attempt to
+ * ensure that the pixels have been decoded.
+ * If this is called on more than one bitmap in sequence, the priority is
+ * given in LRU order (i.e. the last bitmap called will be given highest
+ * priority).
+ *
+ * For bitmaps with no associated caches, this call is effectively a no-op,
+ * and therefore is harmless.
+ */
+ public void prepareToDraw() {
+ nativePrepareToDraw(mNativeBitmap);
+ }
+
+ @Override
protected void finalize() throws Throwable {
try {
nativeDestructor(mNativeBitmap);
@@ -924,7 +940,7 @@ public final class Bitmap implements Parcelable {
super.finalize();
}
}
-
+
//////////// native methods
private static native Bitmap nativeCreate(int[] colors, int offset,
@@ -944,12 +960,12 @@ public final class Bitmap implements Parcelable {
private static native int nativeRowBytes(int nativeBitmap);
private static native int nativeConfig(int nativeBitmap);
private static native boolean nativeHasAlpha(int nativeBitmap);
-
+
private static native int nativeGetPixel(int nativeBitmap, int x, int y);
private static native void nativeGetPixels(int nativeBitmap, int[] pixels,
int offset, int stride, int x,
int y, int width, int height);
-
+
private static native void nativeSetPixel(int nativeBitmap, int x, int y,
int color);
private static native void nativeSetPixels(int nativeBitmap, int[] colors,
@@ -969,6 +985,8 @@ public final class Bitmap implements Parcelable {
int nativePaint,
int[] offsetXY);
+ private static native void nativePrepareToDraw(int nativeBitmap);
+
/* package */ final int ni() {
return mNativeBitmap;
}
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index 9e88d7e..e5a9aab 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -18,18 +18,18 @@ package android.graphics;
import android.content.res.AssetManager;
import android.content.res.Resources;
-import android.util.TypedValue;
import android.util.DisplayMetrics;
+import android.util.TypedValue;
import java.io.BufferedInputStream;
+import java.io.FileDescriptor;
import java.io.FileInputStream;
-import java.io.InputStream;
import java.io.IOException;
-import java.io.FileDescriptor;
+import java.io.InputStream;
/**
- * Creates Bitmap objects from various sources, including files, streams,
- * and byte-arrays.
+ * Creates Bitmap objects from various sources, including files, streams,
+ * and byte-arrays.
*/
public class BitmapFactory {
public static class Options {
@@ -62,7 +62,7 @@ public class BitmapFactory {
* Also, powers of 2 are often faster/easier for the decoder to honor.
*/
public int inSampleSize;
-
+
/**
* If this is non-null, the decoder will try to decode into this
* internal configuration. If it is null, or the request cannot be met,
@@ -71,7 +71,7 @@ public class BitmapFactory {
* as if it has per-pixel alpha (requiring a config that also does).
*/
public Bitmap.Config inPreferredConfig;
-
+
/**
* If dither is true, the decoder will atttempt to dither the decoded
* image.
@@ -117,8 +117,6 @@ public class BitmapFactory {
* explicitly make a copy of the input data, and keep that. Even if
* sharing is allowed, the implementation may still decide to make a
* deep copy of the input data.
- *
- * @hide pending API council approval
*/
public boolean inPurgeable;
@@ -127,8 +125,6 @@ public class BitmapFactory {
* false, then this field is ignored. If inPurgeable is true, then this
* field determines whether the bitmap can share a reference to the
* input data (inputstream, array, etc.) or if it must make a deep copy.
- *
- * @hide pending API council approval
*/
public boolean inInputShareable;
@@ -151,12 +147,12 @@ public class BitmapFactory {
* If not know, or there is an error, it is set to null.
*/
public String outMimeType;
-
+
/**
* Temp storage to use for decoding. Suggest 16K or so.
*/
public byte[] inTempStorage;
-
+
private native void requestCancel();
/**
@@ -167,7 +163,7 @@ public class BitmapFactory {
* if the operation is canceled.
*/
public boolean mCancel;
-
+
/**
* This can be called from another thread while this options object is
* inside a decode... call. Calling this will notify the decoder that
@@ -249,7 +245,7 @@ public class BitmapFactory {
if (opts.inDensity == 0) {
opts.inDensity = density == TypedValue.DENSITY_DEFAULT ?
DisplayMetrics.DEFAULT_DENSITY : density;
- }
+ }
float scale = opts.inDensity / (float) DisplayMetrics.DEFAULT_DENSITY;
if (opts.inScaled || isNinePatch) {
@@ -291,7 +287,7 @@ public class BitmapFactory {
*/
public static Bitmap decodeResource(Resources res, int id, Options opts) {
Bitmap bm = null;
-
+
try {
final TypedValue value = new TypedValue();
final InputStream is = res.openRawResource(id, value);
@@ -306,7 +302,7 @@ public class BitmapFactory {
}
return bm;
}
-
+
/**
* Decode an image referenced by a resource ID.
*
@@ -337,7 +333,7 @@ public class BitmapFactory {
}
return nativeDecodeByteArray(data, offset, length, opts);
}
-
+
/**
* Decode an immutable bitmap from the specified byte array.
*
@@ -350,13 +346,13 @@ public class BitmapFactory {
public static Bitmap decodeByteArray(byte[] data, int offset, int length) {
return decodeByteArray(data, offset, length, null);
}
-
+
/**
* Decode an input stream into a bitmap. If the input stream is null, or
* cannot be used to decode a bitmap, the function returns null.
* The stream's position will be where ever it was after the encoded data
* was read.
- *
+ *
* @param is The input stream that holds the raw data to be decoded into a
* bitmap.
* @param outPadding If not null, return the padding rect for the bitmap if
@@ -375,7 +371,7 @@ public class BitmapFactory {
if (is == null) {
return null;
}
-
+
// we need mark/reset to work properly
if (!is.markSupported()) {
@@ -413,7 +409,7 @@ public class BitmapFactory {
* cannot be used to decode a bitmap, the function returns null.
* The stream's position will be where ever it was after the encoded data
* was read.
- *
+ *
* @param is The input stream that holds the raw data to be decoded into a
* bitmap.
* @return The decoded bitmap, or null if the image data could not be
@@ -441,7 +437,7 @@ public class BitmapFactory {
public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {
return nativeDecodeFileDescriptor(fd, outPadding, opts);
}
-
+
/**
* Decode a bitmap from the file descriptor. If the bitmap cannot be decoded
* return null. The position within the descriptor will not be changed when
@@ -453,7 +449,7 @@ public class BitmapFactory {
public static Bitmap decodeFileDescriptor(FileDescriptor fd) {
return nativeDecodeFileDescriptor(fd, null, null);
}
-
+
private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage,
Rect padding, Options opts);
private static native Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 06d53e3..4498e1a 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1404,7 +1404,11 @@ public class Canvas {
protected void finalize() throws Throwable {
super.finalize();
- finalizer(mNativeCanvas);
+ // If the constructor threw an exception before setting mNativeCanvas, the native finalizer
+ // must not be invoked.
+ if (mNativeCanvas != 0) {
+ finalizer(mNativeCanvas);
+ }
}
/**
diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java
index 2b24ef2..778c903 100644
--- a/graphics/java/android/graphics/NinePatch.java
+++ b/graphics/java/android/graphics/NinePatch.java
@@ -57,7 +57,9 @@ public class NinePatch {
mBitmap = patch.mBitmap;
mChunk = patch.mChunk;
mSrcName = patch.mSrcName;
- mPaint = new Paint(patch.mPaint);
+ if (patch.mPaint != null) {
+ mPaint = new Paint(patch.mPaint);
+ }
validateNinePatchChunk(mBitmap.ni(), mChunk);
}
@@ -120,7 +122,6 @@ public class NinePatch {
public native static boolean isNinePatchChunk(byte[] chunk);
- private final Rect mRect = new Rect();
private final Bitmap mBitmap;
private final byte[] mChunk;
private Paint mPaint;
diff --git a/graphics/java/android/graphics/drawable/Animatable.java b/graphics/java/android/graphics/drawable/Animatable.java
new file mode 100644
index 0000000..9dc62c3
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/Animatable.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2009 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;
+
+/**
+ * Interface that drawables suporting animations should implement.
+ */
+public interface Animatable {
+ /**
+ * Starts the drawable's animation.
+ */
+ void start();
+
+ /**
+ * Stops the drawable's animation.
+ */
+ void stop();
+
+ /**
+ * Indicates whether the animation is running.
+ *
+ * @return True if the animation is running, false otherwise.
+ */
+ boolean isRunning();
+}
diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
new file mode 100644
index 0000000..ac96f20
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2009 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 android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.ColorFilter;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.util.Log;
+import android.os.SystemClock;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+import com.android.internal.R;
+
+/**
+ * @hide
+ */
+public class AnimatedRotateDrawable extends Drawable implements Drawable.Callback, Runnable,
+ Animatable {
+
+ private AnimatedRotateState mState;
+ private boolean mMutated;
+ private float mCurrentDegrees;
+ private float mIncrement;
+ private boolean mRunning;
+
+ public AnimatedRotateDrawable() {
+ this(null);
+ }
+
+ private AnimatedRotateDrawable(AnimatedRotateState rotateState) {
+ mState = new AnimatedRotateState(rotateState, this);
+ init();
+ }
+
+ private void init() {
+ final AnimatedRotateState state = mState;
+ mIncrement = 360.0f / (float) state.mFramesCount;
+ final Drawable drawable = state.mDrawable;
+ if (drawable != null) {
+ drawable.setFilterBitmap(true);
+ if (drawable instanceof BitmapDrawable) {
+ ((BitmapDrawable) drawable).setAntiAlias(true);
+ }
+ }
+ }
+
+ public void draw(Canvas canvas) {
+ int saveCount = canvas.save();
+
+ final AnimatedRotateState st = mState;
+ final Drawable drawable = st.mDrawable;
+ final Rect bounds = drawable.getBounds();
+
+ int w = bounds.right - bounds.left;
+ int h = bounds.bottom - bounds.top;
+
+ float px = st.mPivotXRel ? (w * st.mPivotX) : st.mPivotX;
+ float py = st.mPivotYRel ? (h * st.mPivotY) : st.mPivotY;
+
+ canvas.rotate(mCurrentDegrees, px, py);
+
+ drawable.draw(canvas);
+
+ canvas.restoreToCount(saveCount);
+ }
+
+ public void start() {
+ if (!mRunning) {
+ mRunning = true;
+ nextFrame();
+ }
+ }
+
+ public void stop() {
+ mRunning = false;
+ unscheduleSelf(this);
+ }
+
+ public boolean isRunning() {
+ return mRunning;
+ }
+
+ private void nextFrame() {
+ unscheduleSelf(this);
+ scheduleSelf(this, SystemClock.uptimeMillis() + mState.mFrameDuration);
+ }
+
+ public void run() {
+ // TODO: This should be computed in draw(Canvas), based on the amount
+ // of time since the last frame drawn
+ mCurrentDegrees += mIncrement;
+ if (mCurrentDegrees > (360.0f - mIncrement)) {
+ mCurrentDegrees = 0.0f;
+ }
+ invalidateSelf();
+ nextFrame();
+ }
+
+ @Override
+ public boolean setVisible(boolean visible, boolean restart) {
+ mState.mDrawable.setVisible(visible, restart);
+ boolean changed = super.setVisible(visible, restart);
+ if (visible) {
+ if (changed || restart) {
+ mCurrentDegrees = 0.0f;
+ nextFrame();
+ }
+ } else {
+ unscheduleSelf(this);
+ }
+ return changed;
+ }
+
+ /**
+ * Returns the drawable rotated by this RotateDrawable.
+ */
+ public Drawable getDrawable() {
+ return mState.mDrawable;
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return super.getChangingConfigurations()
+ | mState.mChangingConfigurations
+ | mState.mDrawable.getChangingConfigurations();
+ }
+
+ public void setAlpha(int alpha) {
+ mState.mDrawable.setAlpha(alpha);
+ }
+
+ public void setColorFilter(ColorFilter cf) {
+ mState.mDrawable.setColorFilter(cf);
+ }
+
+ public int getOpacity() {
+ return mState.mDrawable.getOpacity();
+ }
+
+ public void invalidateDrawable(Drawable who) {
+ if (mCallback != null) {
+ mCallback.invalidateDrawable(this);
+ }
+ }
+
+ public void scheduleDrawable(Drawable who, Runnable what, long when) {
+ if (mCallback != null) {
+ mCallback.scheduleDrawable(this, what, when);
+ }
+ }
+
+ public void unscheduleDrawable(Drawable who, Runnable what) {
+ if (mCallback != null) {
+ mCallback.unscheduleDrawable(this, what);
+ }
+ }
+
+ @Override
+ public boolean getPadding(Rect padding) {
+ return mState.mDrawable.getPadding(padding);
+ }
+
+ @Override
+ public boolean isStateful() {
+ return mState.mDrawable.isStateful();
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ mState.mDrawable.setBounds(bounds.left, bounds.top, bounds.right, bounds.bottom);
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mState.mDrawable.getIntrinsicWidth();
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mState.mDrawable.getIntrinsicHeight();
+ }
+
+ @Override
+ public ConstantState getConstantState() {
+ if (mState.canConstantState()) {
+ mState.mChangingConfigurations = super.getChangingConfigurations();
+ return mState;
+ }
+ return null;
+ }
+
+ @Override
+ public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+
+ final TypedArray a = r.obtainAttributes(attrs, R.styleable.AnimatedRotateDrawable);
+
+ super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedRotateDrawable_visible);
+
+ TypedValue tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotX);
+ final boolean pivotXRel = tv.type == TypedValue.TYPE_FRACTION;
+ final float pivotX = pivotXRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
+
+ tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotY);
+ final boolean pivotYRel = tv.type == TypedValue.TYPE_FRACTION;
+ final float pivotY = pivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
+
+ final int framesCount = a.getInt(R.styleable.AnimatedRotateDrawable_framesCount, 12);
+ final int frameDuration = a.getInt(R.styleable.AnimatedRotateDrawable_frameDuration, 150);
+
+ final int res = a.getResourceId(R.styleable.AnimatedRotateDrawable_drawable, 0);
+ Drawable drawable = null;
+ if (res > 0) {
+ drawable = r.getDrawable(res);
+ }
+
+ a.recycle();
+
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT &&
+ (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ if ((drawable = Drawable.createFromXmlInner(r, parser, attrs)) == null) {
+ Log.w("drawable", "Bad element under <animated-rotate>: "
+ + parser .getName());
+ }
+ }
+
+ if (drawable == null) {
+ Log.w("drawable", "No drawable specified for <animated-rotate>");
+ }
+
+ final AnimatedRotateState rotateState = mState;
+ rotateState.mDrawable = drawable;
+ rotateState.mPivotXRel = pivotXRel;
+ rotateState.mPivotX = pivotX;
+ rotateState.mPivotYRel = pivotYRel;
+ rotateState.mPivotY = pivotY;
+ rotateState.mFramesCount = framesCount;
+ rotateState.mFrameDuration = frameDuration;
+
+ init();
+
+ if (drawable != null) {
+ drawable.setCallback(this);
+ }
+ }
+
+ @Override
+ public Drawable mutate() {
+ if (!mMutated && super.mutate() == this) {
+ mState.mDrawable.mutate();
+ mMutated = true;
+ }
+ return this;
+ }
+
+ final static class AnimatedRotateState extends Drawable.ConstantState {
+ Drawable mDrawable;
+
+ int mChangingConfigurations;
+
+ boolean mPivotXRel;
+ float mPivotX;
+ boolean mPivotYRel;
+ float mPivotY;
+ int mFrameDuration;
+ int mFramesCount;
+
+ private boolean mCanConstantState;
+ private boolean mCheckedConstantState;
+
+ public AnimatedRotateState(AnimatedRotateState source, AnimatedRotateDrawable owner) {
+ if (source != null) {
+ mDrawable = source.mDrawable.getConstantState().newDrawable();
+ mDrawable.setCallback(owner);
+ mPivotXRel = source.mPivotXRel;
+ mPivotX = source.mPivotX;
+ mPivotYRel = source.mPivotYRel;
+ mPivotY = source.mPivotY;
+ mFramesCount = source.mFramesCount;
+ mFrameDuration = source.mFrameDuration;
+ mCanConstantState = mCheckedConstantState = true;
+ }
+ }
+
+ @Override
+ public Drawable newDrawable() {
+ return new AnimatedRotateDrawable(this);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return mChangingConfigurations;
+ }
+
+ public boolean canConstantState() {
+ if (!mCheckedConstantState) {
+ mCanConstantState = mDrawable.getConstantState() != null;
+ mCheckedConstantState = true;
+ }
+
+ return mCanConstantState;
+ }
+ }
+}
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index bab1703..68718c9 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -71,7 +71,7 @@ import android.util.AttributeSet;
* @attr ref android.R.styleable#AnimationDrawableItem_duration
* @attr ref android.R.styleable#AnimationDrawableItem_drawable
*/
-public class AnimationDrawable extends DrawableContainer implements Runnable {
+public class AnimationDrawable extends DrawableContainer implements Runnable, Animatable {
private final AnimationState mAnimationState;
private int mCurFrame = -1;
private boolean mMutated;
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index f0d49f5..910e111 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -745,6 +745,8 @@ public abstract class Drawable {
drawable = new ClipDrawable();
} else if (name.equals("rotate")) {
drawable = new RotateDrawable();
+ } else if (name.equals("animated-rotate")) {
+ drawable = new AnimatedRotateDrawable();
} else if (name.equals("animation-list")) {
drawable = new AnimationDrawable();
} else if (name.equals("inset")) {
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index f8b88d0..376b1df 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -234,8 +234,10 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
@Override
public Drawable mutate() {
if (!mMutated && super.mutate() == this) {
- for (Drawable child : mDrawableContainerState.mDrawables) {
- child.mutate();
+ final int N = mDrawableContainerState.getChildCount();
+ final Drawable[] drawables = mDrawableContainerState.getChildren();
+ for (int i = 0; i < N; i++) {
+ drawables[i].mutate();
}
mMutated = true;
}
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 3db45f0..a7a8708 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -880,7 +880,9 @@ public class GradientDrawable extends Drawable {
mShape = state.mShape;
mGradient = state.mGradient;
mOrientation = state.mOrientation;
- mColors = state.mColors.clone();
+ if (state.mColors != null) {
+ mColors = state.mColors.clone();
+ }
if (state.mPositions != null) {
mPositions = state.mPositions.clone();
}