diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-02-10 15:44:00 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-02-10 15:44:00 -0800 |
commit | d24b8183b93e781080b2c16c487e60d51c12da31 (patch) | |
tree | fbb89154858984eb8e41556da7e9433040d55cd4 /graphics/java | |
parent | f1e484acb594a726fb57ad0ae4cfe902c7f35858 (diff) | |
download | frameworks_base-d24b8183b93e781080b2c16c487e60d51c12da31.zip frameworks_base-d24b8183b93e781080b2c16c487e60d51c12da31.tar.gz frameworks_base-d24b8183b93e781080b2c16c487e60d51c12da31.tar.bz2 |
auto import from //branches/cupcake/...@130745
Diffstat (limited to 'graphics/java')
24 files changed, 995 insertions, 392 deletions
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index dc16c39..0b398bc 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -16,18 +16,25 @@ package android.graphics; -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.io.OutputStream; +import android.os.Parcelable; +import android.os.Parcel; + import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.ShortBuffer; import java.nio.IntBuffer; - -import android.os.Parcel; -import android.os.Parcelable; +import java.io.OutputStream; public final class Bitmap implements Parcelable { + /** + * Indicates that the bitmap was created for an unknown pixel density. + * + * @see Bitmap#getDensityScale() + * @see Bitmap#setDensityScale(float) + * + * @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 @@ -41,6 +48,9 @@ public final class Bitmap implements Parcelable { private static volatile Matrix sScaleMatrix; + private float mDensityScale = DENSITY_SCALE_UNKNOWN; + private boolean mAutoScaling; + /** * @noinspection UnusedDeclaration */ @@ -59,6 +69,104 @@ public final class Bitmap implements Parcelable { mIsMutable = isMutable; mNinePatchChunk = ninePatchChunk; } + + /** + * <p>Returns the density scale for this bitmap, expressed as a factor of + * the default density (160.) For instance, a bitmap designed for + * displays with a density of 240 will have a density scale of 1.5 whereas a bitmap + * designed for a density of 160 will have a density scale of 1.0.</p> + * + * <p>The default density scale is {@link #DENSITY_SCALE_UNKNOWN}.</p> + * + * @return A scaling factor of the default density (160) or {@link #DENSITY_SCALE_UNKNOWN} + * if the scaling factor is unknown. + * + * @see #setDensityScale(float) + * @see #isAutoScalingEnabled() + * @see #setAutoScalingEnabled(boolean) + * @see android.util.DisplayMetrics#DEFAULT_DENSITY + * @see android.util.DisplayMetrics#density + * @see #DENSITY_SCALE_UNKNOWN + * + * @hide pending API council approval + */ + public float getDensityScale() { + return mDensityScale; + } + + /** + * <p>Specifies the density scale for this bitmap, expressed as a factor of + * the default density (160.) For instance, a bitmap designed for + * displays with a density of 240 will have a density scale of 1.5 whereas a bitmap + * designed for a density of 160 will have a density scale of 1.0.</p> + * + * @param densityScale The density scaling factor to use with this bitmap or + * {@link #DENSITY_SCALE_UNKNOWN} if the factor is unknown. + * + * @see #getDensityScale() + * @see #isAutoScalingEnabled() + * @see #setAutoScalingEnabled(boolean) + * @see android.util.DisplayMetrics#DEFAULT_DENSITY + * @see android.util.DisplayMetrics#density + * @see #DENSITY_SCALE_UNKNOWN + * + * @hide pending API council approval + */ + public void setDensityScale(float densityScale) { + mDensityScale = densityScale; + } + + /** + * </p>Indicates whether this bitmap will be automatically be scaled at the + * target's density at drawing time. If auto scaling is enabled, this bitmap + * will be drawn with the following scale factor:</p> + * + * <pre>scale = (bitmap density scale factor) / (target density scale factor)</pre> + * + * <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) + * @see #getDensityScale() + * @see #setDensityScale(float) + * + * @hide pending API council approval + */ + public boolean isAutoScalingEnabled() { + return mAutoScaling; + } + + /** + * <p>Enables or disables auto scaling for this bitmap. When auto scaling is enabled, + * the bitmap will be scaled at drawing time to accomodate the drawing target's pixel + * density. The final scale factor for this bitmap is thus defined:</p> + * + * <pre>scale = (bitmap density scale factor) / (target density scale factor)</pre> + * + * <p>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> + * + * @param autoScalingEnabled True to scale the bitmap at drawing time, false otherwise. + * + * @hide pending API council approval + */ + public void setAutoScalingEnabled(boolean autoScalingEnabled) { + mAutoScaling = autoScalingEnabled; + } + + /** + * Sets the nine patch chunk. + * + * @param chunk The definition of the nine patch + * + * @hide + */ + public void setNinePatchChunk(byte[] chunk) { + mNinePatchChunk = chunk; + } /** * Free up the memory associated with this bitmap's pixels, and mark the @@ -126,7 +234,7 @@ public final class Bitmap implements Parcelable { throw new IllegalArgumentException("height must be > 0"); } } - + public enum Config { // these native values must match up with the enum in SkBitmap.h ALPHA_8 (2), @@ -232,7 +340,7 @@ public final class Bitmap implements Parcelable { public static Bitmap createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter) { - Matrix m = null; + Matrix m; synchronized (Bitmap.class) { // small pool of just 1 matrix m = sScaleMatrix; @@ -279,8 +387,7 @@ public final class Bitmap implements Parcelable { * @param width The number of pixels in each row * @param height The number of rows */ - public static Bitmap createBitmap(Bitmap source, int x, int y, - int width, int height) { + public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height) { return createBitmap(source, x, y, width, height, null, false); } @@ -301,23 +408,21 @@ public final class Bitmap implements Parcelable { * @throws IllegalArgumentException if the x, y, width, height values are * outside of the dimensions of the source bitmap. */ - public static Bitmap createBitmap(Bitmap source, int x, int y, int width, - int height, Matrix m, boolean filter) { + public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height, + Matrix m, boolean filter) { + checkXYSign(x, y); checkWidthHeight(width, height); if (x + width > source.getWidth()) { - throw new IllegalArgumentException( - "x + width must be <= bitmap.width()"); + throw new IllegalArgumentException("x + width must be <= bitmap.width()"); } if (y + height > source.getHeight()) { - throw new IllegalArgumentException( - "y + height must be <= bitmap.height()"); + throw new IllegalArgumentException("y + height must be <= bitmap.height()"); } // check if we can just return our argument unchanged - if (!source.isMutable() && x == 0 && y == 0 - && width == source.getWidth() && height == source.getHeight() - && (m == null || m.isIdentity())) { + if (!source.isMutable() && x == 0 && y == 0 && width == source.getWidth() && + height == source.getHeight() && (m == null || m.isIdentity())) { return source; } @@ -331,8 +436,8 @@ public final class Bitmap implements Parcelable { RectF dstR = new RectF(0, 0, width, height); if (m == null || m.isIdentity()) { - bitmap = createBitmap(neww, newh, source.hasAlpha() ? - Config.ARGB_8888 : Config.RGB_565); + bitmap = createBitmap(neww, newh, + source.hasAlpha() ? Config.ARGB_8888 : Config.RGB_565); paint = null; // not needed } else { /* the dst should have alpha if the src does, or if our matrix @@ -343,8 +448,7 @@ public final class Bitmap implements Parcelable { m.mapRect(deviceR, dstR); neww = Math.round(deviceR.width()); newh = Math.round(deviceR.height()); - bitmap = createBitmap(neww, newh, hasAlpha ? - Config.ARGB_8888 : Config.RGB_565); + bitmap = createBitmap(neww, newh, hasAlpha ? Config.ARGB_8888 : Config.RGB_565); if (hasAlpha) { bitmap.eraseColor(0); } @@ -358,7 +462,12 @@ public final class Bitmap implements Parcelable { } canvas.setBitmap(bitmap); canvas.drawBitmap(source, srcR, dstR, paint); - + + // The new bitmap was created from a known bitmap source so assume that + // they use the same density scale + bitmap.setDensityScale(source.getDensityScale()); + bitmap.setAutoScalingEnabled(source.isAutoScalingEnabled()); + return bitmap; } @@ -371,8 +480,7 @@ public final class Bitmap implements Parcelable { * @throws IllegalArgumentException if the width or height are <= 0 */ public static Bitmap createBitmap(int width, int height, Config config) { - Bitmap bm = nativeCreate(null, 0, width, width, height, - config.nativeInt, true); + Bitmap bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true); bm.eraseColor(0); // start with black/transparent pixels return bm; } @@ -395,16 +503,16 @@ public final class Bitmap implements Parcelable { * the color array's length is less than the number of pixels. */ public static Bitmap createBitmap(int colors[], int offset, int stride, - int width, int height, Config config) { + int width, int height, Config config) { + checkWidthHeight(width, height); if (Math.abs(stride) < width) { throw new IllegalArgumentException("abs(stride) must be >= width"); } int lastScanline = offset + (height - 1) * stride; int length = colors.length; - if (offset < 0 || (offset + width > length) - || lastScanline < 0 - || (lastScanline + width > length)) { + if (offset < 0 || (offset + width > length) || lastScanline < 0 || + (lastScanline + width > length)) { throw new ArrayIndexOutOfBoundsException(); } return nativeCreate(colors, offset, stride, width, height, @@ -425,8 +533,7 @@ public final class Bitmap implements Parcelable { * @throws IllegalArgumentException if the width or height are <= 0, or if * the color array's length is less than the number of pixels. */ - public static Bitmap createBitmap(int colors[], int width, int height, - Config config) { + public static Bitmap createBitmap(int colors[], int width, int height, Config config) { return createBitmap(colors, 0, width, width, height, config); } @@ -474,8 +581,7 @@ public final class Bitmap implements Parcelable { * @param stream The outputstream to write the compressed data. * @return true if successfully compressed to the specified stream. */ - public boolean compress(CompressFormat format, int quality, - OutputStream stream) { + public boolean compress(CompressFormat format, int quality, OutputStream stream) { checkRecycled("Can't compress a recycled bitmap"); // do explicit check before calling the native method if (stream == null) { @@ -506,6 +612,32 @@ public final class Bitmap implements Parcelable { } /** + * Convenience method that returns the width of this bitmap divided + * by the density scale factor. + * + * @return The scaled width of this bitmap, according to the density scale factor. + * + * @hide pending API council approval + */ + public int getScaledWidth() { + final float scale = getDensityScale(); + return scale == DENSITY_SCALE_UNKNOWN ? getWidth() : (int) (getWidth() / scale); + } + + /** + * Convenience method that returns the height of this bitmap divided + * by the density scale factor. + * + * @return The scaled height of this bitmap, according to the density scale factor. + * + * @hide pending API council approval + */ + public int getScaledHeight() { + final float scale = getDensityScale(); + return scale == DENSITY_SCALE_UNKNOWN ? getWidth() : (int) (getHeight() / scale); + } + + /** * Return the number of bytes between rows in the bitmap's pixels. Note that * this refers to the pixels as stored natively by the bitmap. If you call * getPixels() or setPixels(), then the pixels are uniformly treated as @@ -836,7 +968,7 @@ public final class Bitmap implements Parcelable { private static native Bitmap nativeExtractAlpha(int nativeBitmap, int nativePaint, int[] offsetXY); - + /* package */ final int ni() { return mNativeBitmap; } diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java index 2c3f543..3813d8f 100644 --- a/graphics/java/android/graphics/BitmapFactory.java +++ b/graphics/java/android/graphics/BitmapFactory.java @@ -18,26 +18,20 @@ package android.graphics; import android.content.res.AssetManager; import android.content.res.Resources; -import android.util.Log; +import android.util.TypedValue; +import android.util.DisplayMetrics; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.InputStream; import java.io.IOException; import java.io.FileDescriptor; -import java.nio.ByteBuffer; -import java.nio.IntBuffer; -import java.nio.ShortBuffer; - /** * Creates Bitmap objects from various sources, including files, streams, * and byte-arrays. */ public class BitmapFactory { - private static final String TAG = "BitmapFactory"; - private static final boolean DEBUG_LOAD = false; - public static class Options { /** * Create a default Options object, which if left unchanged will give @@ -45,6 +39,8 @@ public class BitmapFactory { */ public Options() { inDither = true; + inDensity = 0; + inScaled = true; } /** @@ -53,6 +49,7 @@ public class BitmapFactory { * the bitmap without having to allocate the memory for its pixels. */ public boolean inJustDecodeBounds; + /** * If set to a value > 1, requests the decoder to subsample the original * image, returning a smaller image to save memory. The sample size is @@ -80,20 +77,45 @@ public class BitmapFactory { * image. */ public boolean inDither; - + + /** + * The desired pixel density of the bitmap. + * + * @see android.util.DisplayMetrics#DEFAULT_DENSITY + * @see android.util.DisplayMetrics#density + * + * @hide pending API council approval + */ + public int inDensity; + + /** + * </p>If the bitmap is loaded from {@link android.content.res.Resources} and + * this flag is turned on, the bitmap will be scaled to match the default + * display's pixel density.</p> + * + * </p>This flag is turned on by default and should be turned off if you need + * a non-scaled version of the bitmap. In this case, + * {@link android.graphics.Bitmap#setAutoScalingEnabled(boolean)} can be used + * to properly scale the bitmap at drawing time.</p> + * + * @hide pending API council approval + */ + public boolean inScaled; + /** * The resulting width of the bitmap, set independent of the state of * inJustDecodeBounds. However, if there is an error trying to decode, * outWidth will be set to -1. */ public int outWidth; + /** * The resulting height of the bitmap, set independent of the state of * inJustDecodeBounds. However, if there is an error trying to decode, * outHeight will be set to -1. */ public int outHeight; - + /** * If known, this string is set to the mimetype of the decoded image. * If not know, or there is an error, it is set to null. @@ -103,7 +125,7 @@ public class BitmapFactory { /** * Temp storage to use for decoding. Suggest 16K or so. */ - public byte [] inTempStorage; + public byte[] inTempStorage; private native void requestCancel(); @@ -175,6 +197,58 @@ public class BitmapFactory { } /** + * Decode a new Bitmap from an InputStream. This InputStream was obtained from + * resources, which we pass to be able to scale the bitmap accordingly. + * + * @hide + */ + public static Bitmap decodeStream(Resources res, TypedValue value, InputStream is, + Rect pad, Options opts) { + + if (opts == null) { + opts = new Options(); + } + + Bitmap bm = decodeStream(is, pad, opts); + + if (bm != null && res != null && value != null) { + byte[] np = bm.getNinePatchChunk(); + final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np); + + final int density = value.density; + 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) { + bm.setDensityScale(1.0f); + bm.setAutoScalingEnabled(false); + // Assume we are going to prescale for the screen + scale = res.getDisplayMetrics().density / scale; + if (scale != 1.0f) { + // TODO: This is very inefficient and should be done in native by Skia + final Bitmap oldBitmap = bm; + bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f), + (int) (bm.getHeight() * scale + 0.5f), true); + oldBitmap.recycle(); + + if (isNinePatch) { + np = nativeScaleNinePatch(np, scale, pad); + bm.setNinePatchChunk(np); + } + } + } else { + bm.setDensityScale(scale); + bm.setAutoScalingEnabled(true); + } + } + + return bm; + } + + /** * Decode an image referenced by a resource ID. * * @param res The resources object containing the image data @@ -189,11 +263,12 @@ public class BitmapFactory { Bitmap bm = null; try { - InputStream is = res.openRawResource(id); - bm = decodeStream(is, null, opts); + final TypedValue value = new TypedValue(); + final InputStream is = res.openRawResource(id, value); + + bm = decodeStream(res, value, is, null, opts); is.close(); - } - catch (java.io.IOException e) { + } catch (java.io.IOException e) { /* do nothing. If the exception happened on open, bm will be null. If it happened on close, bm is still valid. @@ -226,8 +301,7 @@ public class BitmapFactory { * decoded, or, if opts is non-null, if opts requested only the * size be returned (in opts.outWidth and opts.outHeight) */ - public static Bitmap decodeByteArray(byte[] data, int offset, int length, - Options opts) { + public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts) { if ((offset | length) < 0 || data.length < offset + length) { throw new ArrayIndexOutOfBoundsException(); } @@ -265,8 +339,7 @@ public class BitmapFactory { * decoded, or, if opts is non-null, if opts requested only the * size be returned (in opts.outWidth and opts.outHeight) */ - public static Bitmap decodeStream(InputStream is, Rect outPadding, - Options opts) { + public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) { // we don't throw in this case, thus allowing the caller to only check // the cache, and not force the image to be decoded. if (is == null) { @@ -287,11 +360,9 @@ public class BitmapFactory { Bitmap bm; if (is instanceof AssetManager.AssetInputStream) { - bm = nativeDecodeAsset( - ((AssetManager.AssetInputStream)is).getAssetInt(), outPadding, - opts); - } - else { + bm = nativeDecodeAsset(((AssetManager.AssetInputStream) is).getAssetInt(), + outPadding, opts); + } else { // pass some temp storage down to the native code. 1024 is made up, // but should be large enough to avoid too many small calls back // into is.read(...) This number is not related to the value passed @@ -337,8 +408,7 @@ public class BitmapFactory { * image should be completely decoded, or just is size returned. * @return the decoded bitmap, or null */ - public static Bitmap decodeFileDescriptor(FileDescriptor fd, - Rect outPadding, Options opts) { + public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) { return nativeDecodeFileDescriptor(fd, outPadding, opts); } @@ -354,13 +424,13 @@ public class BitmapFactory { return nativeDecodeFileDescriptor(fd, null, null); } - private static native Bitmap nativeDecodeStream(InputStream is, - byte[] storage, Rect padding, Options opts); + private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage, + Rect padding, Options opts); private static native Bitmap nativeDecodeFileDescriptor(FileDescriptor fd, - Rect padding, Options opts); - private static native Bitmap nativeDecodeAsset(int asset, Rect padding, - Options opts); + Rect padding, Options opts); + private static native Bitmap nativeDecodeAsset(int asset, Rect padding, Options opts); private static native Bitmap nativeDecodeByteArray(byte[] data, int offset, - int length, Options opts); + int length, Options opts); + private static native byte[] nativeScaleNinePatch(byte[] chunk, float scale, Rect pad); } diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index b57f428..32ecd9f 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -50,6 +50,8 @@ public class Canvas { // Used by native code @SuppressWarnings({"UnusedDeclaration"}) private int mSurfaceFormat; + @SuppressWarnings({"UnusedDeclaration"}) + private float mDensityScale = 1.0f; /** * Construct an empty raster canvas. Use setBitmap() to specify a bitmap to @@ -74,6 +76,8 @@ public class Canvas { throwIfRecycled(bitmap); mNativeCanvas = initRaster(bitmap.ni()); mBitmap = bitmap; + mDensityScale = bitmap.getDensityScale(); + if (mDensityScale == Bitmap.DENSITY_SCALE_UNKNOWN) mDensityScale = 1.0f; } /*package*/ Canvas(int nativeCanvas) { @@ -126,6 +130,8 @@ public class Canvas { native_setBitmap(mNativeCanvas, bitmap.ni()); mBitmap = bitmap; + mDensityScale = bitmap.getDensityScale(); + if (mDensityScale == Bitmap.DENSITY_SCALE_UNKNOWN) mDensityScale = 1.0f; } /** @@ -163,6 +169,51 @@ public class Canvas { */ public native int getHeight(); + /** + * <p>Returns the density scale for this Canvas' backing bitmap, expressed as a + * factor of the default density (160dpi.) For instance, a bitmap designed for + * 240dpi displays will have a density scale of 1.5 whereas a bitmap + * designed for 160dpi will have a density scale of 1.0.</p> + * + * <p>The default density scale is {@link Bitmap#DENSITY_SCALE_UNKNOWN}.</p> + * + * @return A scaling factor of the default density (160dpi) or + * {@link Bitmap#DENSITY_SCALE_UNKNOWN} if the scaling factor is unknown. + * + * @see #setDensityScale(float) + * @see Bitmap#getDensityScale() + * + * @hide pending API council approval + */ + public float getDensityScale() { + if (mBitmap != null) { + return mBitmap.getDensityScale(); + } + return mDensityScale; + } + + /** + * <p>Specifies the density scale for this Canvas' backing bitmap, expressed as a + * factor of the default density (160dpi.) For instance, a bitmap designed for + * 240dpi displays will have a density scale of 1.5 whereas a bitmap + * designed for 160dpi will have a density scale of 1.0.</p> + * + * @param densityScale The density scaling factor to use with this bitmap or + * {@link Bitmap#DENSITY_SCALE_UNKNOWN} if the factor is unknown. + * + * @see #getDensityScale() + * @see Bitmap#setDensityScale(float) + * + * @hide pending API council approval + */ + public void setDensityScale(float densityScale) { + if (mBitmap != null) { + mBitmap.setDensityScale(densityScale); + } + mDensityScale = densityScale; + if (mDensityScale == Bitmap.DENSITY_SCALE_UNKNOWN) mDensityScale = 1.0f; + } + // the SAVE_FLAG constants must match their native equivalents /** restore the current matrix when restore() is called */ @@ -910,7 +961,8 @@ public class Canvas { public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) { throwIfRecycled(bitmap); native_drawBitmap(mNativeCanvas, bitmap.ni(), left, top, - paint != null ? paint.mNativePaint : 0); + paint != null ? paint.mNativePaint : 0, bitmap.isAutoScalingEnabled(), + bitmap.getDensityScale()); } /** @@ -982,8 +1034,8 @@ public class Canvas { * be 0xFF for every pixel). * @param paint May be null. The paint used to draw the bitmap */ - public void drawBitmap(int[] colors, int offset, int stride, int x, int y, - int width, int height, boolean hasAlpha, + public void drawBitmap(int[] colors, int offset, int stride, float x, + float y, int width, int height, boolean hasAlpha, Paint paint) { // check for valid input if (width < 0) { @@ -1006,11 +1058,20 @@ public class Canvas { return; } // punch down to native for the actual draw - native_drawBitmap(mNativeCanvas, colors, offset, stride, x, y, - width, height, hasAlpha, - paint != null ? paint.mNativePaint : 0); + native_drawBitmap(mNativeCanvas, colors, offset, stride, x, y, width, height, hasAlpha, + paint != null ? paint.mNativePaint : 0); } + /** Legacy version of drawBitmap(int[] colors, ...) that took ints for x,y + */ + public void drawBitmap(int[] colors, int offset, int stride, int x, int y, + int width, int height, boolean hasAlpha, + Paint paint) { + // call through to the common float version + drawBitmap(colors, offset, stride, (float)x, (float)y, width, height, + hasAlpha, paint); + } + /** * Draw the bitmap using the specified matrix. * @@ -1020,7 +1081,7 @@ public class Canvas { */ public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) { nativeDrawBitmapMatrix(mNativeCanvas, bitmap.ni(), matrix.ni(), - paint != null ? paint.mNativePaint : 0); + paint != null ? paint.mNativePaint : 0); } private static void checkRange(int length, int offset, int count) { @@ -1416,25 +1477,27 @@ public class Canvas { float ry, int paint); private static native void native_drawPath(int nativeCanvas, int path, int paint); - private static native void native_drawBitmap(int nativeCanvas, int bitmap, + private native void native_drawBitmap(int nativeCanvas, int bitmap, float left, float top, - int nativePaintOrZero); - private static native void native_drawBitmap(int nativeCanvas, int bitmap, + int nativePaintOrZero, boolean autoScale, + float densityScale); + private native void native_drawBitmap(int nativeCanvas, int bitmap, Rect src, RectF dst, int nativePaintOrZero); private static native void native_drawBitmap(int nativeCanvas, int bitmap, Rect src, Rect dst, int nativePaintOrZero); private static native void native_drawBitmap(int nativeCanvas, int[] colors, - int offset, int stride, int x, - int y, int width, int height, + int offset, int stride, float x, + float y, int width, int height, boolean hasAlpha, int nativePaintOrZero); private static native void nativeDrawBitmapMatrix(int nCanvas, int nBitmap, int nMatrix, int nPaint); private static native void nativeDrawBitmapMesh(int nCanvas, int nBitmap, - int meshWidth, int meshHeight, float[] verts, int vertOffset, - int[] colors, int colorOffset, int nPaint); + int meshWidth, int meshHeight, + float[] verts, int vertOffset, + int[] colors, int colorOffset, int nPaint); private static native void nativeDrawVertices(int nCanvas, int mode, int n, float[] verts, int vertOffset, float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices, diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java index cabd848..2b24ef2 100644 --- a/graphics/java/android/graphics/NinePatch.java +++ b/graphics/java/android/graphics/NinePatch.java @@ -26,10 +26,10 @@ package android.graphics; * way that you define, when content added within the image exceeds the normal * bounds of the graphic. For a thorough explanation of a NinePatch image, * read the discussion in the - * <a href="{@docRoot}reference/available-resources.html#ninepatch">Available - * Resource Types</a> document. + * <a href="{@docRoot}guide/topics/graphics/2d-graphics.html#nine-patch">2D + * Graphics</a> document. * <p> - * The <a href="{@docRoot}reference/draw9patch.html">Draw 9-patch</a> + * The <a href="{@docRoot}guide/developing/tools/draw9patch.html">Draw 9-Patch</a> * tool offers an extremely handy way to create your NinePatch images, * using a WYSIWYG graphics editor. * </p> @@ -50,6 +50,17 @@ public class NinePatch { validateNinePatchChunk(mBitmap.ni(), chunk); } + /** + * @hide + */ + public NinePatch(NinePatch patch) { + mBitmap = patch.mBitmap; + mChunk = patch.mChunk; + mSrcName = patch.mSrcName; + mPaint = new Paint(patch.mPaint); + validateNinePatchChunk(mBitmap.ni(), mChunk); + } + public void setPaint(Paint p) { mPaint = p; } diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java index c6b772e..bab1703 100644 --- a/graphics/java/android/graphics/drawable/AnimationDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java @@ -74,6 +74,7 @@ import android.util.AttributeSet; public class AnimationDrawable extends DrawableContainer implements Runnable { private final AnimationState mAnimationState; private int mCurFrame = -1; + private boolean mMutated; public AnimationDrawable() { this(null); @@ -283,6 +284,15 @@ public class AnimationDrawable extends DrawableContainer implements Runnable { 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; diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java index 7f3df9a..5b32246 100644 --- a/graphics/java/android/graphics/drawable/BitmapDrawable.java +++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java @@ -28,6 +28,7 @@ import android.graphics.Rect; import android.graphics.Shader; import android.graphics.BitmapShader; import android.util.AttributeSet; +import android.util.DisplayMetrics; import android.view.Gravity; import org.xmlpull.v1.XmlPullParser; @@ -62,9 +63,12 @@ public class BitmapDrawable extends Drawable { private boolean mApplyGravity; private boolean mRebuildShader; + private int mBitmapWidth; + private int mBitmapHeight; + private boolean mMutated; public BitmapDrawable() { - mBitmapState = new BitmapState(null); + mBitmapState = new BitmapState((Bitmap) null); } public BitmapDrawable(Bitmap bitmap) { @@ -92,7 +96,62 @@ public class BitmapDrawable extends Drawable { public final Bitmap getBitmap() { return mBitmap; } - + + private void setBitmap(Bitmap bitmap) { + mBitmap = bitmap; + if (bitmap != null) { + mBitmapWidth = bitmap.getWidth(); + mBitmapHeight = bitmap.getHeight(); + } else { + mBitmapWidth = mBitmapHeight = -1; + } + } + + /** + * Set the density scale at which this drawable will be rendered. This + * method assumes the drawable will be rendered at the same density as the + * specified canvas. + * + * @param canvas The Canvas from which the density scale must be obtained. + * + * @see android.graphics.Bitmap#setDensityScale(float) + * @see android.graphics.Bitmap#getDensityScale() + * + * @hide pending API council approval + */ + public void setDensityScale(Canvas canvas) { + setDensityScale(canvas.getDensityScale()); + } + + /** + * Set the density scale at which this drawable will be rendered. + * + * @param metrics The DisplayMetrics indicating the density scale for this drawable. + * + * @see android.graphics.Bitmap#setDensityScale(float) + * @see android.graphics.Bitmap#getDensityScale() + * + * @hide pending API council approval + */ + public void setDensityScale(DisplayMetrics metrics) { + setDensityScale(metrics.density); + } + + /** + * Set the density scale at which this drawable will be rendered. + * + * @param density The density scale for this drawable. + * + * @see android.graphics.Bitmap#setDensityScale(float) + * @see android.graphics.Bitmap#getDensityScale() + * + * @hide pending API council approval + */ + public void setDensityScale(float density) { + density = (density == Bitmap.DENSITY_SCALE_UNKNOWN ? 1.0f : density); + mBitmapState.mTargetDensityScale = density; + } + /** Get the gravity used to position/stretch the bitmap within its bounds. See android.view.Gravity * @return the gravity applied to the bitmap @@ -184,7 +243,7 @@ public class BitmapDrawable extends Drawable { Shader shader = state.mPaint.getShader(); if (shader == null) { if (mApplyGravity) { - Gravity.apply(state.mGravity, bitmap.getWidth(), bitmap.getHeight(), + Gravity.apply(state.mGravity, mBitmapWidth, mBitmapHeight, getBounds(), mDstRect); mApplyGravity = false; } @@ -209,6 +268,21 @@ public class BitmapDrawable extends Drawable { mBitmapState.mPaint.setColorFilter(cf); } + /** + * A mutable BitmapDrawable still shares its Bitmap with any other Drawable + * that comes from the same resource. + * + * @return This drawable. + */ + @Override + public Drawable mutate() { + if (!mMutated && super.mutate() == this) { + mBitmapState = new BitmapState(mBitmapState); + mMutated = true; + } + return this; + } + @Override public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException, IOException { @@ -226,7 +300,9 @@ public class BitmapDrawable extends Drawable { throw new XmlPullParserException(parser.getPositionDescription() + ": <bitmap> requires a valid src attribute"); } - mBitmapState.mBitmap = mBitmap = bitmap; + mBitmapState.mBitmap = bitmap; + setBitmap(bitmap); + setDensityScale(r.getDisplayMetrics()); final Paint paint = mBitmapState.mPaint; paint.setAntiAlias(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_antialias, @@ -256,14 +332,29 @@ public class BitmapDrawable extends Drawable { @Override public int getIntrinsicWidth() { - Bitmap bitmap = mBitmap; - return bitmap != null ? bitmap.getWidth() : -1; + final Bitmap bitmap = mBitmap; + final BitmapState state = mBitmapState; + + if (!state.mAutoScale || state.mBitmapScale == Bitmap.DENSITY_SCALE_UNKNOWN) { + return mBitmapWidth; + } else { + return bitmap != null ? (int) (mBitmapWidth / + (state.mBitmapScale / state.mTargetDensityScale) + 0.5f) : -1; + + } } @Override public int getIntrinsicHeight() { - Bitmap bitmap = mBitmap; - return bitmap != null ? bitmap.getHeight() : -1; + final Bitmap bitmap = mBitmap; + final BitmapState state = mBitmapState; + + if (!state.mAutoScale || state.mBitmapScale == Bitmap.DENSITY_SCALE_UNKNOWN) { + return mBitmapHeight; + } else { + return bitmap != null ? (int) (mBitmapHeight / + (state.mBitmapScale / state.mTargetDensityScale) + 0.5f) : -1; + } } @Override @@ -289,9 +380,29 @@ public class BitmapDrawable extends Drawable { Paint mPaint = new Paint(DEFAULT_PAINT_FLAGS); Shader.TileMode mTileModeX; Shader.TileMode mTileModeY; + boolean mAutoScale; + float mBitmapScale; + float mTargetDensityScale = 1.0f; BitmapState(Bitmap bitmap) { mBitmap = bitmap; + if (bitmap != null) { + mBitmapScale = bitmap.getDensityScale(); + mAutoScale = bitmap.isAutoScalingEnabled(); + } else { + mBitmapScale = 1.0f; + mAutoScale = false; + } + } + + BitmapState(BitmapState bitmapState) { + this(bitmapState.mBitmap); + mChangingConfigurations = bitmapState.mChangingConfigurations; + mGravity = bitmapState.mGravity; + mTileModeX = bitmapState.mTileModeX; + mTileModeY = bitmapState.mTileModeY; + mTargetDensityScale = bitmapState.mTargetDensityScale; + mPaint = new Paint(bitmapState.mPaint); } @Override @@ -307,6 +418,6 @@ public class BitmapDrawable extends Drawable { private BitmapDrawable(BitmapState state) { mBitmapState = state; - mBitmap = state.mBitmap; + setBitmap(state.mBitmap); } } diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java index 6029388..95d4dd0 100644 --- a/graphics/java/android/graphics/drawable/ClipDrawable.java +++ b/graphics/java/android/graphics/drawable/ClipDrawable.java @@ -24,7 +24,6 @@ import android.content.res.TypedArray; import android.graphics.*; import android.view.Gravity; import android.util.AttributeSet; -import android.util.Log; import java.io.IOException; @@ -100,9 +99,8 @@ public class ClipDrawable extends Drawable implements Drawable.Callback { mClipState.mDrawable = dr; mClipState.mOrientation = orientation; mClipState.mGravity = g; - if (dr != null) { - dr.setCallback(this); - } + + dr.setCallback(this); } // overrides from Drawable.Callback @@ -168,8 +166,7 @@ public class ClipDrawable extends Drawable implements Drawable.Callback { @Override protected boolean onStateChange(int[] state) { - boolean changed = mClipState.mDrawable.setState(state); - return changed; + return mClipState.mDrawable.setState(state); } @Override @@ -233,7 +230,17 @@ public class ClipDrawable extends Drawable implements Drawable.Callback { return null; } + + final static class ClipState extends ConstantState { + Drawable mDrawable; + int mChangingConfigurations; + int mOrientation; + int mGravity; + + private boolean mCheckedConstantState; + private boolean mCanConstantState; + ClipState(ClipState orig, ClipDrawable owner) { if (orig != null) { mDrawable = orig.mDrawable.getConstantState().newDrawable(); @@ -262,14 +269,6 @@ public class ClipDrawable extends Drawable implements Drawable.Callback { return mCanConstantState; } - - Drawable mDrawable; - int mChangingConfigurations; - int mOrientation; - int mGravity; - - private boolean mCheckedConstantState; - private boolean mCanConstantState; } private ClipDrawable(ClipState state) { diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index 0021241..cf72f38 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -29,6 +29,7 @@ import android.graphics.*; import android.util.AttributeSet; import android.util.StateSet; import android.util.Xml; +import android.util.TypedValue; /** * A Drawable is a general abstraction for "something that can be drawn." Most @@ -91,7 +92,7 @@ import android.util.Xml; * whose overall size is modified based on the current level. * </ul> * <p>For information and examples of creating drawable resources (XML or bitmap files that - * can be loaded in code), see <a href="{@docRoot}devel/resources-i18n.html">Resources + * can be loaded in code), see <a href="{@docRoot}guide/topics/resources/resources-i18n.html">Resources * and Internationalization</a>. */ public abstract class Drawable { @@ -102,7 +103,7 @@ public abstract class Drawable { private Rect mBounds = new Rect(); /*package*/ Callback mCallback = null; private boolean mVisible = true; - + /** * Draw in its bounds (set via setBounds) respecting optional effects such * as alpha (set via setAlpha) and color filter (set via setColorFilter). @@ -618,9 +619,36 @@ public abstract class Drawable { } /** + * Make this drawable mutable. This operation cannot be reversed. A mutable + * drawable is guaranteed to not share its state with any other drawable. + * This is especially useful when you need to modify properties of drawables + * loaded from resources. By default, all drawables instances loaded from + * the same resource share a common state; if you modify the state of one + * instance, all the other instances will receive the same modification. + * + * Calling this method on a mutable Drawable will have no effect. + * + * @return This drawable. + */ + public Drawable mutate() { + return this; + } + + /** * Create a drawable from an inputstream */ public static Drawable createFromStream(InputStream is, String srcName) { + return createFromResourceStream(null, null, is, srcName); + } + + /** + * Create a drawable from an inputstream + * + * @hide pending API council approval + */ + public static Drawable createFromResourceStream(Resources res, TypedValue value, + InputStream is, String srcName) { + if (is == null) { return null; } @@ -632,14 +660,14 @@ public abstract class Drawable { Rects only to drop them on the floor. */ Rect pad = new Rect(); - Bitmap bm = BitmapFactory.decodeStream(is, pad, null); + Bitmap bm = BitmapFactory.decodeStream(res, value, is, pad, null); if (bm != null) { byte[] np = bm.getNinePatchChunk(); if (np == null || !NinePatch.isNinePatchChunk(np)) { np = null; pad = null; } - return drawableFromBitmap(bm, np, pad, srcName); + return drawableFromBitmap(res, bm, np, pad, srcName); } return null; } @@ -647,7 +675,7 @@ public abstract class Drawable { /** * Create a drawable from an XML document. For more information on how to * create resources in XML, see - * <a href="{@docRoot}devel/resources-i18n.html">Resources and + * <a href="{@docRoot}guide/topics/resources/resources-i18n.html">Resources and * Internationalization</a>. */ public static Drawable createFromXml(Resources r, XmlPullParser parser) @@ -708,6 +736,9 @@ public abstract class Drawable { drawable = new InsetDrawable(); } else if (name.equals("bitmap")) { drawable = new BitmapDrawable(); + if (r != null) { + ((BitmapDrawable) drawable).setDensityScale(r.getDisplayMetrics()); + } } else { throw new XmlPullParserException(parser.getPositionDescription() + ": invalid drawable tag " + name); @@ -728,7 +759,7 @@ public abstract class Drawable { Bitmap bm = BitmapFactory.decodeFile(pathName); if (bm != null) { - return drawableFromBitmap(bm, null, null, pathName); + return drawableFromBitmap(null, bm, null, null, pathName); } return null; @@ -758,11 +789,19 @@ public abstract class Drawable { return null; } - private static Drawable drawableFromBitmap(Bitmap bm, byte[] np, Rect pad, String srcName) { + private static Drawable drawableFromBitmap(Resources res, Bitmap bm, byte[] np, + Rect pad, String srcName) { + if (np != null) { return new NinePatchDrawable(bm, np, pad, srcName); } - return new BitmapDrawable(bm); + + final BitmapDrawable drawable = new BitmapDrawable(bm); + if (res != null) { + drawable.setDensityScale(res.getDisplayMetrics()); + } + + return drawable; } } diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index e6c48be..29f2a00 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -21,12 +21,13 @@ import android.graphics.*; public class DrawableContainer extends Drawable implements Drawable.Callback { private DrawableContainerState mDrawableContainerState; - private Drawable mCurrDrawable; - private int mAlpha = 0xFF; - private ColorFilter mColorFilter; - private boolean mDither; + private Drawable mCurrDrawable; + private int mAlpha = 0xFF; + private ColorFilter mColorFilter; + private boolean mDither; - private int mCurIndex = -1; + private int mCurIndex = -1; + private boolean mMutated; // overrides from Drawable @@ -229,6 +230,17 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { return null; } + @Override + public Drawable mutate() { + if (!mMutated && super.mutate() == this) { + for (Drawable child : mDrawableContainerState.mDrawables) { + child.mutate(); + } + mMutated = true; + } + return this; + } + public abstract static class DrawableContainerState extends ConstantState { final DrawableContainer mOwner; @@ -277,7 +289,9 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { mCheckedConstantState = mCanConstantState = true; mVariablePadding = orig.mVariablePadding; - mConstantPadding = orig.mConstantPadding; + if (orig.mConstantPadding != null) { + mConstantPadding = new Rect(orig.mConstantPadding); + } mConstantSize = orig.mConstantSize; mComputedConstantSize = orig.mComputedConstantSize; mConstantWidth = orig.mConstantWidth; diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java index cdfca1b..82cb795 100644 --- a/graphics/java/android/graphics/drawable/GradientDrawable.java +++ b/graphics/java/android/graphics/drawable/GradientDrawable.java @@ -106,20 +106,21 @@ public class GradientDrawable extends Drawable { */ public static final int SWEEP_GRADIENT = 2; - private final GradientState mGradientState; + private GradientState mGradientState; private final Paint mFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - private Rect mPadding; - private Paint mStrokePaint; // optional, set by the caller + private Rect mPadding; + private Paint mStrokePaint; // optional, set by the caller private ColorFilter mColorFilter; // optional, set by the caller - private int mAlpha = 0xFF; // modified by the caller - private boolean mDither; + private int mAlpha = 0xFF; // modified by the caller + private boolean mDither; - private final Path mPath = new Path(); + private final Path mPath = new Path(); private final RectF mRect = new RectF(); - private Paint mLayerPaint; // internal, used if we use saveLayer() - private boolean mRectIsDirty; // internal state + private Paint mLayerPaint; // internal, used if we use saveLayer() + private boolean mRectIsDirty; // internal state + private boolean mMutated; /** * Controls how the gradient is oriented relative to the drawable's bounds @@ -791,31 +792,41 @@ public class GradientDrawable extends Drawable { return mGradientState; } + @Override + public Drawable mutate() { + if (!mMutated && super.mutate() == this) { + mGradientState = new GradientState(mGradientState); + initializeWithState(mGradientState); + mMutated = true; + } + return this; + } + final static class GradientState extends ConstantState { - public int mChangingConfigurations; - public int mShape = RECTANGLE; - public int mGradient = LINEAR_GRADIENT; - public Orientation mOrientation; - public int[] mColors; - public float[] mPositions; - public boolean mHasSolidColor; - public int mSolidColor; - public int mStrokeWidth = -1; // if >= 0 use stroking. - public int mStrokeColor; - public float mStrokeDashWidth; - public float mStrokeDashGap; - public float mRadius; // use this if mRadiusArray is null - public float[] mRadiusArray; - public Rect mPadding; - public int mWidth = -1; - public int mHeight = -1; - public float mInnerRadius; - public float mThickness; - private float mCenterX = 0.5f; - private float mCenterY = 0.5f; - private float mGradientRadius = 0.5f; - private boolean mUseLevel; - private boolean mUseLevelForShape; + public int mChangingConfigurations; + public int mShape = RECTANGLE; + public int mGradient = LINEAR_GRADIENT; + public Orientation mOrientation; + public int[] mColors; + public float[] mPositions; + public boolean mHasSolidColor; + public int mSolidColor; + public int mStrokeWidth = -1; // if >= 0 use stroking. + public int mStrokeColor; + public float mStrokeDashWidth; + public float mStrokeDashGap; + public float mRadius; // use this if mRadiusArray is null + public float[] mRadiusArray; + public Rect mPadding; + public int mWidth = -1; + public int mHeight = -1; + public float mInnerRadius; + public float mThickness; + private float mCenterX = 0.5f; + private float mCenterY = 0.5f; + private float mGradientRadius = 0.5f; + private boolean mUseLevel; + private boolean mUseLevelForShape; GradientState() { @@ -827,6 +838,32 @@ public class GradientDrawable extends Drawable { mColors = colors; } + public GradientState(GradientState state) { + mChangingConfigurations = state.mChangingConfigurations; + mShape = state.mShape; + mGradient = state.mGradient; + mOrientation = state.mOrientation; + mColors = state.mColors.clone(); + mPositions = state.mPositions.clone(); + mHasSolidColor = state.mHasSolidColor; + mStrokeWidth = state.mStrokeWidth; + mStrokeColor = state.mStrokeColor; + mStrokeDashWidth = state.mStrokeDashWidth; + mStrokeDashGap = state.mStrokeDashGap; + mRadius = state.mRadius; + mRadiusArray = state.mRadiusArray.clone(); + mPadding = new Rect(state.mPadding); + mWidth = state.mWidth; + mHeight = state.mHeight; + mInnerRadius = state.mInnerRadius; + mThickness = state.mThickness; + mCenterX = state.mCenterX; + mCenterY = state.mCenterY; + mGradientRadius = state.mGradientRadius; + mUseLevel = state.mUseLevel; + mUseLevelForShape = state.mUseLevelForShape; + } + @Override public Drawable newDrawable() { return new GradientDrawable(this); @@ -895,6 +932,11 @@ public class GradientDrawable extends Drawable { private GradientDrawable(GradientState state) { mGradientState = state; + initializeWithState(state); + mRectIsDirty = true; + } + + private void initializeWithState(GradientState state) { if (state.mHasSolidColor) { mFillPaint.setColor(state.mSolidColor); } @@ -906,12 +948,11 @@ public class GradientDrawable extends Drawable { mStrokePaint.setColor(state.mStrokeColor); if (state.mStrokeDashWidth != 0.0f) { - DashPathEffect e = new DashPathEffect(new float[] { - state.mStrokeDashWidth, state.mStrokeDashGap}, 0); + DashPathEffect e = new DashPathEffect( + new float[] { state.mStrokeDashWidth, state.mStrokeDashGap }, 0); mStrokePaint.setPathEffect(e); } } - mRectIsDirty = true; } } diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java index 80b8e96..6047726 100644 --- a/graphics/java/android/graphics/drawable/InsetDrawable.java +++ b/graphics/java/android/graphics/drawable/InsetDrawable.java @@ -44,6 +44,9 @@ import java.io.IOException; public class InsetDrawable extends Drawable implements Drawable.Callback { // Most of this is copied from ScaleDrawable. + private InsetState mInsetState; + private final Rect mTmpRect = new Rect(); + private boolean mMutated; /*package*/ InsetDrawable() { this(null); @@ -239,7 +242,27 @@ public class InsetDrawable extends Drawable implements Drawable.Callback return null; } + @Override + public Drawable mutate() { + if (!mMutated && super.mutate() == this) { + mInsetState.mDrawable.mutate(); + mMutated = true; + } + return this; + } + final static class InsetState extends ConstantState { + Drawable mDrawable; + int mChangingConfigurations; + + int mInsetLeft; + int mInsetTop; + int mInsetRight; + int mInsetBottom; + + boolean mCheckedConstantState; + boolean mCanConstantState; + InsetState(InsetState orig, InsetDrawable owner) { if (orig != null) { mDrawable = orig.mDrawable.getConstantState().newDrawable(); @@ -270,25 +293,10 @@ public class InsetDrawable extends Drawable implements Drawable.Callback return mCanConstantState; } - - Drawable mDrawable; - int mChangingConfigurations; - - int mInsetLeft; - int mInsetTop; - int mInsetRight; - int mInsetBottom; - - boolean mCheckedConstantState; - boolean mCanConstantState; } private InsetDrawable(InsetState state) { - InsetState as = new InsetState(state, this); - mInsetState = as; + mInsetState = new InsetState(state, this); } - - private InsetState mInsetState; - private final Rect mTmpRect = new Rect(); } diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java index 59dfbd4..c777205 100644 --- a/graphics/java/android/graphics/drawable/LayerDrawable.java +++ b/graphics/java/android/graphics/drawable/LayerDrawable.java @@ -51,6 +51,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { private int[] mPaddingB; private final Rect mTmpRect = new Rect(); + private boolean mMutated; /** * Create a new layer drawable with the list of specified layers. @@ -71,16 +72,16 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { LayerDrawable(Drawable[] layers, LayerState state) { this(state); int length = layers.length; - Rec[] r = new Rec[length]; + ChildDrawable[] r = new ChildDrawable[length]; for (int i = 0; i < length; i++) { - r[i] = new Rec(); + r[i] = new ChildDrawable(); r[i].mDrawable = layers[i]; layers[i].setCallback(this); mLayerState.mChildrenChangingConfigurations |= layers[i].getChangingConfigurations(); } mLayerState.mNum = length; - mLayerState.mArray = r; + mLayerState.mChildren = r; ensurePadding(); } @@ -171,26 +172,26 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { */ private void addLayer(Drawable layer, int id, int left, int top, int right, int bottom) { final LayerState st = mLayerState; - int N = st.mArray != null ? st.mArray.length : 0; + int N = st.mChildren != null ? st.mChildren.length : 0; int i = st.mNum; if (i >= N) { - Rec[] nu = new Rec[N + 10]; + ChildDrawable[] nu = new ChildDrawable[N + 10]; if (i > 0) { - System.arraycopy(st.mArray, 0, nu, 0, i); + System.arraycopy(st.mChildren, 0, nu, 0, i); } - st.mArray = nu; + st.mChildren = nu; } mLayerState.mChildrenChangingConfigurations |= layer.getChangingConfigurations(); - Rec rec = new Rec(); - st.mArray[i] = rec; - rec.mId = id; - rec.mDrawable = layer; - rec.mInsetL = left; - rec.mInsetT = top; - rec.mInsetR = right; - rec.mInsetB = bottom; + ChildDrawable childDrawable = new ChildDrawable(); + st.mChildren[i] = childDrawable; + childDrawable.mId = id; + childDrawable.mDrawable = layer; + childDrawable.mInsetL = left; + childDrawable.mInsetT = top; + childDrawable.mInsetR = right; + childDrawable.mInsetB = bottom; st.mNum++; layer.setCallback(this); @@ -203,7 +204,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { * @return The {@link Drawable} of the layer that has the given id in the hierarchy or null. */ public Drawable findDrawableByLayerId(int id) { - final Rec[] layers = mLayerState.mArray; + final ChildDrawable[] layers = mLayerState.mChildren; for (int i = mLayerState.mNum - 1; i >= 0; i--) { if (layers[i].mId == id) { @@ -221,7 +222,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { * @param id The ID to assign to the layer. */ public void setId(int index, int id) { - mLayerState.mArray[index].mId = id; + mLayerState.mChildren[index].mId = id; } /** @@ -240,7 +241,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { * @return The {@link android.graphics.drawable.Drawable} at the specified layer index. */ public Drawable getDrawable(int index) { - return mLayerState.mArray[index].mDrawable; + return mLayerState.mChildren[index].mDrawable; } /** @@ -251,7 +252,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { * @return The id of the layer or {@link android.view.View#NO_ID} if the layer has no id. */ public int getId(int index) { - return mLayerState.mArray[index].mId; + return mLayerState.mChildren[index].mId; } /** @@ -263,7 +264,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { * the id was not found). */ public boolean setDrawableByLayerId(int id, Drawable drawable) { - final Rec[] layers = mLayerState.mArray; + final ChildDrawable[] layers = mLayerState.mChildren; for (int i = mLayerState.mNum - 1; i >= 0; i--) { if (layers[i].mId == id) { @@ -282,11 +283,11 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { bottom -= b; */ public void setLayerInset(int index, int l, int t, int r, int b) { - Rec rec = mLayerState.mArray[index]; - rec.mInsetL = l; - rec.mInsetT = t; - rec.mInsetR = r; - rec.mInsetB = b; + ChildDrawable childDrawable = mLayerState.mChildren[index]; + childDrawable.mInsetL = l; + childDrawable.mInsetT = t; + childDrawable.mInsetR = r; + childDrawable.mInsetB = b; } // overrides from Drawable.Callback @@ -313,7 +314,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { @Override public void draw(Canvas canvas) { - final Rec[] array = mLayerState.mArray; + final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i=0; i<N; i++) { array[i].mDrawable.draw(canvas); @@ -336,7 +337,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { padding.top = 0; padding.right = 0; padding.bottom = 0; - final Rec[] array = mLayerState.mArray; + final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i=0; i<N; i++) { reapplyPadding(i, array[i]); @@ -351,7 +352,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { @Override public boolean setVisible(boolean visible, boolean restart) { boolean changed = super.setVisible(visible, restart); - final Rec[] array = mLayerState.mArray; + final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i=0; i<N; i++) { array[i].mDrawable.setVisible(visible, restart); @@ -361,7 +362,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { @Override public void setDither(boolean dither) { - final Rec[] array = mLayerState.mArray; + final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i=0; i<N; i++) { array[i].mDrawable.setDither(dither); @@ -370,7 +371,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { @Override public void setAlpha(int alpha) { - final Rec[] array = mLayerState.mArray; + final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i=0; i<N; i++) { array[i].mDrawable.setAlpha(alpha); @@ -379,7 +380,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { @Override public void setColorFilter(ColorFilter cf) { - final Rec[] array = mLayerState.mArray; + final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i=0; i<N; i++) { array[i].mDrawable.setColorFilter(cf); @@ -398,12 +399,12 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { @Override protected boolean onStateChange(int[] state) { - final Rec[] array = mLayerState.mArray; + final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; boolean paddingChanged = false; boolean changed = false; for (int i=0; i<N; i++) { - final Rec r = array[i]; + final ChildDrawable r = array[i]; if (r.mDrawable.setState(state)) { changed = true; } @@ -419,12 +420,12 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { @Override protected boolean onLevelChange(int level) { - final Rec[] array = mLayerState.mArray; + final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; boolean paddingChanged = false; boolean changed = false; for (int i=0; i<N; i++) { - final Rec r = array[i]; + final ChildDrawable r = array[i]; if (r.mDrawable.setLevel(level)) { changed = true; } @@ -440,11 +441,11 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { @Override protected void onBoundsChange(Rect bounds) { - final Rec[] array = mLayerState.mArray; + final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; int padL=0, padT=0, padR=0, padB=0; for (int i=0; i<N; i++) { - final Rec r = array[i]; + final ChildDrawable r = array[i]; r.mDrawable.setBounds(bounds.left + r.mInsetL + padL, bounds.top + r.mInsetT + padT, bounds.right - r.mInsetR - padR, @@ -459,11 +460,11 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { @Override public int getIntrinsicWidth() { int width = -1; - final Rec[] array = mLayerState.mArray; + final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; int padL=0, padR=0; for (int i=0; i<N; i++) { - final Rec r = array[i]; + final ChildDrawable r = array[i]; int w = r.mDrawable.getIntrinsicWidth() + r.mInsetL + r.mInsetR + padL + padR; if (w > width) { @@ -478,11 +479,11 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { @Override public int getIntrinsicHeight() { int height = -1; - final Rec[] array = mLayerState.mArray; + final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; int padT=0, padB=0; for (int i=0; i<N; i++) { - final Rec r = array[i]; + final ChildDrawable r = array[i]; int h = r.mDrawable.getIntrinsicHeight() + r.mInsetT + r.mInsetB + + padT + padB; if (h > height) { height = h; @@ -493,7 +494,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { return height; } - private boolean reapplyPadding(int i, Rec r) { + private boolean reapplyPadding(int i, ChildDrawable r) { final Rect rect = mTmpRect; r.mDrawable.getPadding(rect); if (rect.left != mPaddingL[i] || rect.top != mPaddingT[i] || @@ -527,7 +528,20 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { return null; } - static class Rec { + @Override + public Drawable mutate() { + if (!mMutated && super.mutate() == this) { + final ChildDrawable[] array = mLayerState.mChildren; + final int N = mLayerState.mNum; + for (int i = 0; i < N; i++) { + array[i].mDrawable.mutate(); + } + mMutated = true; + } + return this; + } + + static class ChildDrawable { public Drawable mDrawable; public int mInsetL, mInsetT, mInsetR, mInsetB; public int mId; @@ -535,7 +549,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { static class LayerState extends ConstantState { int mNum; - Rec[] mArray; + ChildDrawable[] mChildren; int mChangingConfigurations; int mChildrenChangingConfigurations; @@ -551,18 +565,18 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { LayerState(LayerState orig, LayerDrawable owner) { if (orig != null) { - final Rec[] origRec = orig.mArray; + final ChildDrawable[] origChildDrawable = orig.mChildren; final int N = orig.mNum; mNum = N; - mArray = new Rec[N]; + mChildren = new ChildDrawable[N]; mChangingConfigurations = orig.mChangingConfigurations; mChildrenChangingConfigurations = orig.mChildrenChangingConfigurations; for (int i = 0; i < N; i++) { - final Rec r = mArray[i] = new Rec(); - final Rec or = origRec[i]; + final ChildDrawable r = mChildren[i] = new ChildDrawable(); + final ChildDrawable or = origChildDrawable[i]; r.mDrawable = or.mDrawable.getConstantState().newDrawable(); r.mDrawable.setCallback(owner); r.mInsetL = or.mInsetL; @@ -579,7 +593,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { mCheckedConstantState = mCanConstantState = true; } else { mNum = 0; - mArray = null; + mChildren = null; } } @@ -599,11 +613,9 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } final int N = mNum; - int op = N > 0 ? mArray[0].mDrawable.getOpacity() - : PixelFormat.TRANSPARENT; + int op = N > 0 ? mChildren[0].mDrawable.getOpacity() : PixelFormat.TRANSPARENT; for (int i = 1; i < N; i++) { - op = Drawable.resolveOpacity(op, mArray[i].mDrawable - .getOpacity()); + op = Drawable.resolveOpacity(op, mChildren[i].mDrawable.getOpacity()); } mOpacity = op; mHaveOpacity = true; @@ -618,7 +630,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { boolean stateful = false; final int N = mNum; for (int i = 0; i < N; i++) { - if (mArray[i].mDrawable.isStateful()) { + if (mChildren[i].mDrawable.isStateful()) { stateful = true; break; } @@ -630,11 +642,11 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } public synchronized boolean canConstantState() { - if (!mCheckedConstantState && mArray != null) { + if (!mCheckedConstantState && mChildren != null) { mCanConstantState = true; final int N = mNum; for (int i=0; i<N; i++) { - if (mArray[i].mDrawable.getConstantState() == null) { + if (mChildren[i].mDrawable.getConstantState() == null) { mCanConstantState = false; break; } diff --git a/graphics/java/android/graphics/drawable/LevelListDrawable.java b/graphics/java/android/graphics/drawable/LevelListDrawable.java index 93dc32c..cf94a3a 100644 --- a/graphics/java/android/graphics/drawable/LevelListDrawable.java +++ b/graphics/java/android/graphics/drawable/LevelListDrawable.java @@ -26,24 +26,26 @@ import android.content.res.TypedArray; import android.util.AttributeSet; /** - * - * A resource that manages a number of alternate Drawables, each assigned a maximum numerical value. - * Setting the level value of the object with {@link #setLevel(int)} will load the image with the next - * greater or equal value assigned to its max attribute. - * A good example use of + * A resource that manages a number of alternate Drawables, each assigned a maximum numerical value. + * Setting the level value of the object with {@link #setLevel(int)} will load the image with the next + * greater or equal value assigned to its max attribute. + * A good example use of * a LevelListDrawable would be a battery level indicator icon, with different images to indicate the current * battery level. * <p> * It can be defined in an XML file with the <code><level-list></code> element. * Each Drawable level is defined in a nested <code><item></code> * </p> + * * @attr ref android.R.styleable#LevelListDrawableItem_minLevel * @attr ref android.R.styleable#LevelListDrawableItem_maxLevel * @attr ref android.R.styleable#LevelListDrawableItem_drawable */ public class LevelListDrawable extends DrawableContainer { - public LevelListDrawable() - { + private final LevelListState mLevelListState; + private boolean mMutated; + + public LevelListDrawable() { this(null); } @@ -54,7 +56,7 @@ public class LevelListDrawable extends DrawableContainer { onLevelChange(getLevel()); } } - + // overrides from Drawable @Override @@ -65,21 +67,22 @@ public class LevelListDrawable extends DrawableContainer { } return super.onLevelChange(level); } - - @Override public void inflate(Resources r, XmlPullParser parser, - AttributeSet attrs) - throws XmlPullParserException, IOException { + + @Override + public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs) + throws XmlPullParserException, IOException { + super.inflate(r, parser, attrs); - + int type; int low = 0; - final int innerDepth = parser.getDepth()+1; + final int innerDepth = parser.getDepth() + 1; int depth; - while ((type=parser.next()) != XmlPullParser.END_DOCUMENT - && ((depth=parser.getDepth()) >= innerDepth - || type != XmlPullParser.END_TAG)) { + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && ((depth = parser.getDepth()) >= innerDepth + || type != XmlPullParser.END_TAG)) { if (type != XmlPullParser.START_TAG) { continue; } @@ -87,50 +90,60 @@ public class LevelListDrawable extends DrawableContainer { if (depth > innerDepth || !parser.getName().equals("item")) { continue; } - + TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.LevelListDrawableItem); - + low = a.getInt( com.android.internal.R.styleable.LevelListDrawableItem_minLevel, 0); int high = a.getInt( com.android.internal.R.styleable.LevelListDrawableItem_maxLevel, 0); int drawableRes = a.getResourceId( com.android.internal.R.styleable.LevelListDrawableItem_drawable, 0); - + a.recycle(); - + if (high < 0) { throw new XmlPullParserException(parser.getPositionDescription() - + ": <item> tag requires a 'maxLevel' attribute"); + + ": <item> tag requires a 'maxLevel' attribute"); } - + Drawable dr; if (drawableRes != 0) { dr = r.getDrawable(drawableRes); } else { - while ((type=parser.next()) == XmlPullParser.TEXT) { + while ((type = parser.next()) == XmlPullParser.TEXT) { } if (type != XmlPullParser.START_TAG) { throw new XmlPullParserException( parser.getPositionDescription() - + ": <item> tag requires a 'drawable' attribute or " - + "child tag defining a drawable"); + + ": <item> tag requires a 'drawable' attribute or " + + "child tag defining a drawable"); } dr = Drawable.createFromXmlInner(r, parser, attrs); } mLevelListState.addLevel(low, high, dr); - low = high+1; } onLevelChange(getLevel()); } - private final static class LevelListState extends DrawableContainerState - { - LevelListState(LevelListState orig, LevelListDrawable owner) - { + @Override + public Drawable mutate() { + if (!mMutated && super.mutate() == this) { + mLevelListState.mLows = mLevelListState.mLows.clone(); + mLevelListState.mHighs = mLevelListState.mHighs.clone(); + mMutated = true; + } + return this; + } + + private final static class LevelListState extends DrawableContainerState { + private int[] mLows; + private int[] mHighs; + + LevelListState(LevelListState orig, LevelListDrawable owner) { super(orig, owner); if (orig != null) { @@ -142,19 +155,17 @@ public class LevelListDrawable extends DrawableContainer { } } - public void addLevel(int low, int high, Drawable drawable) - { + public void addLevel(int low, int high, Drawable drawable) { int pos = addChild(drawable); mLows[pos] = low; mHighs[pos] = high; } - public int indexOfLevel(int level) - { + public int indexOfLevel(int level) { final int[] lows = mLows; final int[] highs = mHighs; final int N = getChildCount(); - for (int i=0; i<N; i++) { + for (int i = 0; i < N; i++) { if (level >= lows[i] && level <= highs[i]) { return i; } @@ -163,14 +174,12 @@ public class LevelListDrawable extends DrawableContainer { } @Override - public Drawable newDrawable() - { + public Drawable newDrawable() { return new LevelListDrawable(this); } @Override - public void growArray(int oldSize, int newSize) - { + public void growArray(int oldSize, int newSize) { super.growArray(oldSize, newSize); int[] newInts = new int[newSize]; System.arraycopy(mLows, 0, newInts, 0, oldSize); @@ -179,19 +188,13 @@ public class LevelListDrawable extends DrawableContainer { System.arraycopy(mHighs, 0, newInts, 0, oldSize); mHighs = newInts; } - - private int[] mLows; - private int[] mHighs; } - private LevelListDrawable(LevelListState state) - { + private LevelListDrawable(LevelListState state) { LevelListState as = new LevelListState(state, this); mLevelListState = as; setConstantState(as); onLevelChange(getLevel()); } - - private final LevelListState mLevelListState; } diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java index c98ef5b..3ded37b 100644 --- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java +++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java @@ -26,9 +26,13 @@ import android.graphics.*; * */ public class NinePatchDrawable extends Drawable { + private NinePatchState mNinePatchState; + private NinePatch mNinePatch; + private Rect mPadding; + private Paint mPaint; + private boolean mMutated; - public NinePatchDrawable(Bitmap bitmap, byte[] chunk, - Rect padding, String srcName) { + public NinePatchDrawable(Bitmap bitmap, byte[] chunk, Rect padding, String srcName) { this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding)); } @@ -45,8 +49,7 @@ public class NinePatchDrawable extends Drawable { @Override public int getChangingConfigurations() { - return super.getChangingConfigurations() - | mNinePatchState.mChangingConfigurations; + return super.getChangingConfigurations() | mNinePatchState.mChangingConfigurations; } @Override @@ -104,12 +107,13 @@ public class NinePatchDrawable extends Drawable { } /** - * Returns a {@link android.graphics.PixelFormat graphics.PixelFormat} value of OPAQUE or TRANSLUCENT. + * Returns a {@link android.graphics.PixelFormat graphics.PixelFormat} + * value of OPAQUE or TRANSLUCENT. */ @Override public int getOpacity() { - return mNinePatch.hasAlpha() || (mPaint != null && mPaint.getAlpha() < 255) - ? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE; + return mNinePatch.hasAlpha() || (mPaint != null && mPaint.getAlpha() < 255) ? + PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE; } @Override @@ -123,16 +127,35 @@ public class NinePatchDrawable extends Drawable { return mNinePatchState; } + @Override + public Drawable mutate() { + if (!mMutated && super.mutate() == this) { + mNinePatchState = new NinePatchState(mNinePatchState); + mNinePatch = mNinePatchState.mNinePatch; + mPadding = mNinePatchState.mPadding; + mMutated = true; + } + return this; + } + final static class NinePatchState extends ConstantState { - NinePatchState(NinePatch ninePatch, Rect padding) - { + final NinePatch mNinePatch; + final Rect mPadding; + int mChangingConfigurations; + + NinePatchState(NinePatch ninePatch, Rect padding) { mNinePatch = ninePatch; mPadding = padding; } + NinePatchState(NinePatchState state) { + mNinePatch = new NinePatch(state.mNinePatch); + mPadding = new Rect(state.mPadding); + mChangingConfigurations = state.mChangingConfigurations; + } + @Override - public Drawable newDrawable() - { + public Drawable newDrawable() { return new NinePatchDrawable(this); } @@ -140,10 +163,6 @@ public class NinePatchDrawable extends Drawable { public int getChangingConfigurations() { return mChangingConfigurations; } - - final NinePatch mNinePatch; - final Rect mPadding; - int mChangingConfigurations; } private NinePatchDrawable(NinePatchState state) { @@ -151,10 +170,5 @@ public class NinePatchDrawable extends Drawable { mNinePatch = state.mNinePatch; mPadding = state.mPadding; } - - private final NinePatchState mNinePatchState; - private final NinePatch mNinePatch; - private final Rect mPadding; - private Paint mPaint; } diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java index 3e03ed4..e4b821a 100644 --- a/graphics/java/android/graphics/drawable/RotateDrawable.java +++ b/graphics/java/android/graphics/drawable/RotateDrawable.java @@ -45,6 +45,10 @@ import java.io.IOException; * @attr ref android.R.styleable#RotateDrawable_drawable */ public class RotateDrawable extends Drawable implements Drawable.Callback { + private static final float MAX_LEVEL = 10000.0f; + + private RotateState mState; + private boolean mMutated; /** * <p>Create a new rotating drawable with an empty state.</p> @@ -248,6 +252,15 @@ public class RotateDrawable extends Drawable implements Drawable.Callback { } } + @Override + public Drawable mutate() { + if (!mMutated && super.mutate() == this) { + mState.mDrawable.mutate(); + mMutated = true; + } + return this; + } + /** * <p>Represents the state of a rotation for a given drawable. The same * rotate drawable can be invoked with different states to drive several @@ -268,6 +281,9 @@ public class RotateDrawable extends Drawable implements Drawable.Callback { float mCurrentDegrees; + private boolean mCanConstantState; + private boolean mCheckedConstantState; + public RotateState(RotateState source, RotateDrawable owner) { if (source != null) { mDrawable = source.mDrawable.getConstantState().newDrawable(); @@ -300,12 +316,5 @@ public class RotateDrawable extends Drawable implements Drawable.Callback { return mCanConstantState; } - - private boolean mCanConstantState; - private boolean mCheckedConstantState; } - - private static final float MAX_LEVEL = 10000.0f; - - private RotateState mState; } diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java index c40c8c0..b3322c9 100644 --- a/graphics/java/android/graphics/drawable/ScaleDrawable.java +++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java @@ -24,7 +24,6 @@ import android.content.res.TypedArray; import android.graphics.*; import android.view.Gravity; import android.util.AttributeSet; -import android.util.Log; import java.io.IOException; @@ -44,6 +43,7 @@ import java.io.IOException; */ public class ScaleDrawable extends Drawable implements Drawable.Callback { private ScaleState mScaleState; + private boolean mMutated; private final Rect mTmpRect = new Rect(); ScaleDrawable() { @@ -234,7 +234,25 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback { return null; } + @Override + public Drawable mutate() { + if (!mMutated && super.mutate() == this) { + mScaleState.mDrawable.mutate(); + mMutated = true; + } + return this; + } + final static class ScaleState extends ConstantState { + Drawable mDrawable; + int mChangingConfigurations; + float mScaleWidth; + float mScaleHeight; + int mGravity; + + private boolean mCheckedConstantState; + private boolean mCanConstantState; + ScaleState(ScaleState orig, ScaleDrawable owner) { if (orig != null) { mDrawable = orig.mDrawable.getConstantState().newDrawable(); @@ -264,15 +282,6 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback { return mCanConstantState; } - - Drawable mDrawable; - int mChangingConfigurations; - float mScaleWidth; - float mScaleHeight; - int mGravity; - - private boolean mCheckedConstantState; - private boolean mCanConstantState; } private ScaleDrawable(ScaleState state) { diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java index 7e1284f..d24194f 100644 --- a/graphics/java/android/graphics/drawable/ShapeDrawable.java +++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java @@ -28,15 +28,24 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; /** - * An object that draws primitive shapes. + * A Drawable object that draws primitive shapes. * A ShapeDrawable takes a {@link android.graphics.drawable.shapes.Shape} * object and manages its presence on the screen. If no Shape is given, then * the ShapeDrawable will default to a * {@link android.graphics.drawable.shapes.RectShape}. + * + * @attr ref android.R.styleable#ShapeDrawablePadding_left + * @attr ref android.R.styleable#ShapeDrawablePadding_top + * @attr ref android.R.styleable#ShapeDrawablePadding_right + * @attr ref android.R.styleable#ShapeDrawablePadding_bottom + * @attr ref android.R.styleable#ShapeDrawable_color + * @attr ref android.R.styleable#ShapeDrawable_width + * @attr ref android.R.styleable#ShapeDrawable_height */ public class ShapeDrawable extends Drawable { private ShapeState mShapeState; - + private boolean mMutated; + /** * ShapeDrawable constructor. */ @@ -334,6 +343,21 @@ public class ShapeDrawable extends Drawable { return mShapeState; } + @Override + public Drawable mutate() { + if (!mMutated && super.mutate() == this) { + mShapeState.mPaint = new Paint(mShapeState.mPaint); + mShapeState.mPadding = new Rect(mShapeState.mPadding); + try { + mShapeState.mShape = mShapeState.mShape.clone(); + } catch (CloneNotSupportedException e) { + return null; + } + mMutated = true; + } + return this; + } + /** * Defines the intrinsic properties of this ShapeDrawable's Shape. */ diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java index 1dc1627..475825c 100644 --- a/graphics/java/android/graphics/drawable/StateListDrawable.java +++ b/graphics/java/android/graphics/drawable/StateListDrawable.java @@ -27,10 +27,9 @@ import android.util.AttributeSet; import android.util.StateSet; /** - * * Lets you assign a number of graphic images to a single Drawable and swap out the visible item by a string * ID value. - * + * <p/> * <p>It can be defined in an XML file with the <code><selector></code> element. * Each state Drawable is defined in a nested <code><item></code> element.</p> * @@ -51,15 +50,18 @@ import android.util.StateSet; * @attr ref android.R.styleable#DrawableStates_state_pressed */ public class StateListDrawable extends DrawableContainer { - public StateListDrawable() - { + private final StateListState mStateListState; + private boolean mMutated; + + public StateListDrawable() { this(null); } /** * Add a new image/string ID to the set of images. + * * @param stateSet - An array of resource Ids to associate with the image. - * Switch to this image by calling setState(). + * Switch to this image by calling setState(). * @param drawable -The image to show. */ public void addState(int[] stateSet, Drawable drawable) { @@ -74,7 +76,7 @@ public class StateListDrawable extends DrawableContainer { public boolean isStateful() { return true; } - + @Override protected boolean onStateChange(int[] stateSet) { int idx = mStateListState.indexOfStateSet(stateSet); @@ -87,30 +89,31 @@ public class StateListDrawable extends DrawableContainer { return super.onStateChange(stateSet); } - @Override public void inflate(Resources r, XmlPullParser parser, + @Override + public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs) - throws XmlPullParserException, IOException { - + throws XmlPullParserException, IOException { + TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.StateListDrawable); super.inflateWithAttributes(r, parser, a, com.android.internal.R.styleable.StateListDrawable_visible); - + mStateListState.setVariablePadding(a.getBoolean( com.android.internal.R.styleable.StateListDrawable_variablePadding, false)); mStateListState.setConstantSize(a.getBoolean( com.android.internal.R.styleable.StateListDrawable_constantSize, false)); - + a.recycle(); - + int type; - final int innerDepth = parser.getDepth()+1; + final int innerDepth = parser.getDepth() + 1; int depth; - while ((type=parser.next()) != XmlPullParser.END_DOCUMENT - && ((depth=parser.getDepth()) >= innerDepth - || type != XmlPullParser.END_TAG)) { + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && ((depth = parser.getDepth()) >= innerDepth + || type != XmlPullParser.END_TAG)) { if (type != XmlPullParser.START_TAG) { continue; } @@ -118,9 +121,9 @@ public class StateListDrawable extends DrawableContainer { if (depth > innerDepth || !parser.getName().equals("item")) { continue; } - + int drawableRes = 0; - + int i; int j = 0; final int numAttrs = attrs.getAttributeCount(); @@ -132,27 +135,27 @@ public class StateListDrawable extends DrawableContainer { drawableRes = attrs.getAttributeResourceValue(i, 0); } else { states[j++] = attrs.getAttributeBooleanValue(i, false) - ? stateResId - : -stateResId; + ? stateResId + : -stateResId; } } states = StateSet.trimStateSet(states, j); - + Drawable dr; if (drawableRes != 0) { dr = r.getDrawable(drawableRes); } else { - while ((type=parser.next()) == XmlPullParser.TEXT) { + while ((type = parser.next()) == XmlPullParser.TEXT) { } if (type != XmlPullParser.START_TAG) { throw new XmlPullParserException( parser.getPositionDescription() - + ": <item> tag requires a 'drawable' attribute or " - + "child tag defining a drawable"); + + ": <item> tag requires a 'drawable' attribute or " + + "child tag defining a drawable"); } dr = Drawable.createFromXmlInner(r, parser, attrs); } - + mStateListState.addStateSet(states, dr); } @@ -162,49 +165,63 @@ public class StateListDrawable extends DrawableContainer { StateListState getStateListState() { return mStateListState; } - + /** * Gets the number of states contained in this drawable. - * + * * @return The number of states contained in this drawable. + * @hide pending API council * @see #getStateSet(int) * @see #getStateDrawable(int) - * @hide pending API council */ public int getStateCount() { - return mStateListState.getChildCount(); + return mStateListState.getChildCount(); } /** * Gets the state set at an index. - * + * * @param index The index of the state set. * @return The state set at the index. + * @hide pending API council * @see #getStateCount() * @see #getStateDrawable(int) - * @hide pending API council */ public int[] getStateSet(int index) { return mStateListState.mStateSets[index]; } - + /** * Gets the drawable at an index. - * + * * @param index The index of the drawable. * @return The drawable at the index. + * @hide pending API council * @see #getStateCount() * @see #getStateSet(int) - * @hide pending API council */ public Drawable getStateDrawable(int index) { return mStateListState.getChildren()[index]; } - - static final class StateListState extends DrawableContainerState - { - StateListState(StateListState orig, StateListDrawable owner) - { + + @Override + public Drawable mutate() { + if (!mMutated && super.mutate() == this) { + final int[][] sets = mStateListState.mStateSets; + final int count = sets.length; + mStateListState.mStateSets = new int[count][]; + for (int i = 0; i < count; i++) { + mStateListState.mStateSets[i] = sets[i].clone(); + } + mMutated = true; + } + return this; + } + + static final class StateListState extends DrawableContainerState { + private int[][] mStateSets; + + StateListState(StateListState orig, StateListDrawable owner) { super(orig, owner); if (orig != null) { @@ -220,11 +237,10 @@ public class StateListDrawable extends DrawableContainer { return pos; } - private int indexOfStateSet(int[] stateSet) - { + private int indexOfStateSet(int[] stateSet) { final int[][] stateSets = mStateSets; final int N = getChildCount(); - for (int i=0; i<N; i++) { + for (int i = 0; i < N; i++) { if (StateSet.stateSetMatches(stateSets[i], stateSet)) { return i; } @@ -233,31 +249,24 @@ public class StateListDrawable extends DrawableContainer { } @Override - public Drawable newDrawable() - { + public Drawable newDrawable() { return new StateListDrawable(this); } @Override - public void growArray(int oldSize, int newSize) - { + public void growArray(int oldSize, int newSize) { super.growArray(oldSize, newSize); final int[][] newStateSets = new int[newSize][]; System.arraycopy(mStateSets, 0, newStateSets, 0, oldSize); mStateSets = newStateSets; } - - private int[][] mStateSets; } - private StateListDrawable(StateListState state) - { + private StateListDrawable(StateListState state) { StateListState as = new StateListState(state, this); mStateListState = as; setConstantState(as); onStateChange(getState()); } - - private final StateListState mStateListState; } diff --git a/graphics/java/android/graphics/drawable/TransitionDrawable.java b/graphics/java/android/graphics/drawable/TransitionDrawable.java index a99d4e5..358f889 100644 --- a/graphics/java/android/graphics/drawable/TransitionDrawable.java +++ b/graphics/java/android/graphics/drawable/TransitionDrawable.java @@ -63,7 +63,9 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba private int mFrom; private int mTo; private int mDuration; - private TransitionState mState; + private int mOriginalDuration; + private int mAlpha = 0; + private boolean mCrossFade; /** * Create a new transition drawable with the specified list of layers. At least @@ -85,12 +87,10 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba private TransitionDrawable(TransitionState state) { super(state); - mState = state; } private TransitionDrawable(TransitionState state, Drawable[] layers) { super(layers, state); - mState = state; } @Override @@ -106,8 +106,8 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba public void startTransition(int durationMillis) { mFrom = 0; mTo = 255; - mState.mAlpha = 0; - mState.mDuration = mDuration = durationMillis; + mAlpha = 0; + mDuration = mOriginalDuration = durationMillis; mReverse = false; mTransitionState = TRANSITION_STARTING; invalidateSelf(); @@ -117,7 +117,7 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba * Show only the first layer. */ public void resetTransition() { - mState.mAlpha = 0; + mAlpha = 0; mTransitionState = TRANSITION_NONE; invalidateSelf(); } @@ -133,36 +133,35 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba public void reverseTransition(int duration) { final long time = SystemClock.uptimeMillis(); // Animation is over - if (time - mStartTimeMillis > mState.mDuration) { - if (mState.mAlpha == 0) { + if (time - mStartTimeMillis > mDuration) { + if (mAlpha == 0) { mFrom = 0; mTo = 255; - mState.mAlpha = 0; + mAlpha = 0; mReverse = false; } else { mFrom = 255; mTo = 0; - mState.mAlpha = 255; + mAlpha = 255; mReverse = true; } - mDuration = mState.mDuration = duration; + mDuration = mOriginalDuration = duration; mTransitionState = TRANSITION_STARTING; invalidateSelf(); return; } mReverse = !mReverse; - mFrom = mState.mAlpha; + mFrom = mAlpha; mTo = mReverse ? 0 : 255; mDuration = (int) (mReverse ? time - mStartTimeMillis : - mState.mDuration - (time - mStartTimeMillis)); + mOriginalDuration - (time - mStartTimeMillis)); mTransitionState = TRANSITION_STARTING; } @Override public void draw(Canvas canvas) { boolean done = true; - final TransitionState state = mState; switch (mTransitionState) { case TRANSITION_STARTING: @@ -177,14 +176,14 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba (SystemClock.uptimeMillis() - mStartTimeMillis) / mDuration; done = normalized >= 1.0f; normalized = Math.min(normalized, 1.0f); - state.mAlpha = (int) (mFrom + (mTo - mFrom) * normalized); + mAlpha = (int) (mFrom + (mTo - mFrom) * normalized); } break; } - final int alpha = state.mAlpha; - final boolean crossFade = state.mCrossFade; - final Rec[] array = mLayerState.mArray; + final int alpha = mAlpha; + final boolean crossFade = mCrossFade; + final ChildDrawable[] array = mLayerState.mChildren; Drawable d; d = array[0].mDrawable; @@ -217,7 +216,7 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba * @param enabled True to enable cross fading, false otherwise. */ public void setCrossFadeEnabled(boolean enabled) { - mState.mCrossFade = enabled; + mCrossFade = enabled; } /** @@ -226,14 +225,10 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba * @return True if cross fading is enabled, false otherwise. */ public boolean isCrossFadeEnabled() { - return mState.mCrossFade; + return mCrossFade; } static class TransitionState extends LayerState { - int mAlpha = 0; - int mDuration; - boolean mCrossFade; - TransitionState(TransitionState orig, TransitionDrawable owner) { super(orig, owner); } diff --git a/graphics/java/android/graphics/drawable/package.html b/graphics/java/android/graphics/drawable/package.html index 17ee865..da49df7 100644 --- a/graphics/java/android/graphics/drawable/package.html +++ b/graphics/java/android/graphics/drawable/package.html @@ -4,6 +4,6 @@ Provides classes to manage a variety of visual elements that are intended for display only, such as bitmaps and gradients. These elements are often used by widgets as background images or simply as indicators (for example, a volume level indicator). You can create most of these in XML as described in <a -href="{@docRoot}reference/available-resources.html">Resources</a>. +href="{@docRoot}guide/topics/resources/available-resources.html">Availeble Resource Types</a>. </BODY> </HTML> diff --git a/graphics/java/android/graphics/drawable/shapes/PathShape.java b/graphics/java/android/graphics/drawable/shapes/PathShape.java index 3656a0b..30b7347 100644 --- a/graphics/java/android/graphics/drawable/shapes/PathShape.java +++ b/graphics/java/android/graphics/drawable/shapes/PathShape.java @@ -64,5 +64,12 @@ public class PathShape extends Shape { mScaleX = width / mStdWidth; mScaleY = height / mStdHeight; } + + @Override + public PathShape clone() throws CloneNotSupportedException { + PathShape shape = (PathShape) super.clone(); + shape.mPath = new Path(mPath); + return shape; + } } diff --git a/graphics/java/android/graphics/drawable/shapes/RectShape.java b/graphics/java/android/graphics/drawable/shapes/RectShape.java index 4f038ae..a3d2654 100644 --- a/graphics/java/android/graphics/drawable/shapes/RectShape.java +++ b/graphics/java/android/graphics/drawable/shapes/RectShape.java @@ -50,4 +50,11 @@ public class RectShape extends Shape { protected final RectF rect() { return mRect; } + + @Override + public RectShape clone() throws CloneNotSupportedException { + final RectShape shape = (RectShape) super.clone(); + shape.mRect = new RectF(mRect); + return shape; + } } diff --git a/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java b/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java index 54ef3f7..f4cf15c 100644 --- a/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java +++ b/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java @@ -105,4 +105,15 @@ public class RoundRectShape extends RectShape { } } } + + @Override + public RoundRectShape clone() throws CloneNotSupportedException { + RoundRectShape shape = (RoundRectShape) super.clone(); + shape.mOuterRadii = mOuterRadii.clone(); + shape.mInnerRadii = mInnerRadii.clone(); + shape.mInset = new RectF(mInset); + shape.mInnerRect = new RectF(mInnerRect); + shape.mPath = new Path(mPath); + return shape; + } } diff --git a/graphics/java/android/graphics/drawable/shapes/Shape.java b/graphics/java/android/graphics/drawable/shapes/Shape.java index fc54bc1..4e192f9 100644 --- a/graphics/java/android/graphics/drawable/shapes/Shape.java +++ b/graphics/java/android/graphics/drawable/shapes/Shape.java @@ -25,7 +25,7 @@ import android.graphics.Paint; * but more graphical control is available if you instead pass * it to a {@link android.graphics.drawable.ShapeDrawable}. */ -public abstract class Shape { +public abstract class Shape implements Cloneable { private float mWidth; private float mHeight; @@ -92,4 +92,9 @@ public abstract class Shape { * @param height the new height of the Shape */ protected void onResize(float width, float height) {} + + @Override + public Shape clone() throws CloneNotSupportedException { + return (Shape) super.clone(); + } } |