diff options
Diffstat (limited to 'graphics')
26 files changed, 866 insertions, 363 deletions
diff --git a/graphics/java/android/graphics/AvoidXfermode.java b/graphics/java/android/graphics/AvoidXfermode.java index 206c959..48ee6fa 100644 --- a/graphics/java/android/graphics/AvoidXfermode.java +++ b/graphics/java/android/graphics/AvoidXfermode.java @@ -23,7 +23,7 @@ package android.graphics; @Deprecated public class AvoidXfermode extends Xfermode { - // these need to match the enum in SkAvoidXfermode.h on the native side + // these need to match the enum in AvoidXfermode.h on the native side public enum Mode { AVOID (0), //!< draw everywhere except on the opColor TARGET (1); //!< draw only on top of the opColor diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index 72f6118..132c6ef 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -1537,7 +1537,7 @@ public final class Bitmap implements Parcelable { */ public Bitmap extractAlpha(Paint paint, int[] offsetXY) { checkRecycled("Can't extractAlpha on a recycled bitmap"); - long nativePaint = paint != null ? paint.mNativePaint : 0; + long nativePaint = paint != null ? paint.getNativeInstance() : 0; Bitmap bm = nativeExtractAlpha(mNativeBitmap, nativePaint, offsetXY); if (bm == null) { throw new RuntimeException("Failed to extractAlpha on Bitmap"); diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index b0580d5..e4c2f0e 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -44,8 +44,12 @@ import javax.microedition.khronos.opengles.GL; */ public class Canvas { - // assigned in constructors or setBitmap, freed in finalizer - private long mNativeCanvasWrapper; + /** + * Should only be assigned in constructors (or setBitmap if software canvas), + * freed in finalizer. + * @hide + */ + protected long mNativeCanvasWrapper; /** @hide */ public long getNativeCanvasWrapper() { @@ -475,7 +479,7 @@ public class Canvas { public int saveLayer(float left, float top, float right, float bottom, @Nullable Paint paint, @Saveflags int saveFlags) { return native_saveLayer(mNativeCanvasWrapper, left, top, right, bottom, - paint != null ? paint.mNativePaint : 0, + paint != null ? paint.getNativeInstance() : 0, saveFlags); } @@ -1031,7 +1035,7 @@ public class Canvas { * @param paint The paint used to draw onto the canvas */ public void drawPaint(@NonNull Paint paint) { - native_drawPaint(mNativeCanvasWrapper, paint.mNativePaint); + native_drawPaint(mNativeCanvasWrapper, paint.getNativeInstance()); } /** @@ -1051,7 +1055,7 @@ public class Canvas { * @param paint The paint used to draw the points */ public void drawPoints(float[] pts, int offset, int count, @NonNull Paint paint) { - native_drawPoints(mNativeCanvasWrapper, pts, offset, count, paint.mNativePaint); + native_drawPoints(mNativeCanvasWrapper, pts, offset, count, paint.getNativeInstance()); } /** @@ -1065,7 +1069,7 @@ public class Canvas { * Helper for drawPoints() for drawing a single point. */ public void drawPoint(float x, float y, @NonNull Paint paint) { - native_drawPoint(mNativeCanvasWrapper, x, y, paint.mNativePaint); + native_drawPoint(mNativeCanvasWrapper, x, y, paint.getNativeInstance()); } /** @@ -1082,7 +1086,7 @@ public class Canvas { */ public void drawLine(float startX, float startY, float stopX, float stopY, @NonNull Paint paint) { - native_drawLine(mNativeCanvasWrapper, startX, startY, stopX, stopY, paint.mNativePaint); + native_drawLine(mNativeCanvasWrapper, startX, startY, stopX, stopY, paint.getNativeInstance()); } /** @@ -1101,7 +1105,7 @@ public class Canvas { * @param paint The paint used to draw the points */ public void drawLines(float[] pts, int offset, int count, Paint paint) { - native_drawLines(mNativeCanvasWrapper, pts, offset, count, paint.mNativePaint); + native_drawLines(mNativeCanvasWrapper, pts, offset, count, paint.getNativeInstance()); } public void drawLines(@NonNull float[] pts, @NonNull Paint paint) { @@ -1117,7 +1121,7 @@ public class Canvas { */ public void drawRect(@NonNull RectF rect, @NonNull Paint paint) { native_drawRect(mNativeCanvasWrapper, - rect.left, rect.top, rect.right, rect.bottom, paint.mNativePaint); + rect.left, rect.top, rect.right, rect.bottom, paint.getNativeInstance()); } /** @@ -1143,7 +1147,7 @@ public class Canvas { * @param paint The paint used to draw the rect */ public void drawRect(float left, float top, float right, float bottom, @NonNull Paint paint) { - native_drawRect(mNativeCanvasWrapper, left, top, right, bottom, paint.mNativePaint); + native_drawRect(mNativeCanvasWrapper, left, top, right, bottom, paint.getNativeInstance()); } /** @@ -1164,7 +1168,7 @@ public class Canvas { * filled or framed based on the Style in the paint. */ public void drawOval(float left, float top, float right, float bottom, @NonNull Paint paint) { - native_drawOval(mNativeCanvasWrapper, left, top, right, bottom, paint.mNativePaint); + native_drawOval(mNativeCanvasWrapper, left, top, right, bottom, paint.getNativeInstance()); } /** @@ -1178,7 +1182,7 @@ public class Canvas { * @param paint The paint used to draw the circle */ public void drawCircle(float cx, float cy, float radius, @NonNull Paint paint) { - native_drawCircle(mNativeCanvasWrapper, cx, cy, radius, paint.mNativePaint); + native_drawCircle(mNativeCanvasWrapper, cx, cy, radius, paint.getNativeInstance()); } /** @@ -1234,7 +1238,7 @@ public class Canvas { public void drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint) { native_drawArc(mNativeCanvasWrapper, left, top, right, bottom, startAngle, sweepAngle, - useCenter, paint.mNativePaint); + useCenter, paint.getNativeInstance()); } /** @@ -1260,7 +1264,7 @@ public class Canvas { */ public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, @NonNull Paint paint) { - native_drawRoundRect(mNativeCanvasWrapper, left, top, right, bottom, rx, ry, paint.mNativePaint); + native_drawRoundRect(mNativeCanvasWrapper, left, top, right, bottom, rx, ry, paint.getNativeInstance()); } /** @@ -1271,7 +1275,7 @@ public class Canvas { * @param paint The paint used to draw the path */ public void drawPath(@NonNull Path path, @NonNull Paint paint) { - native_drawPath(mNativeCanvasWrapper, path.ni(), paint.mNativePaint); + native_drawPath(mNativeCanvasWrapper, path.ni(), paint.getNativeInstance()); } /** @@ -1336,7 +1340,7 @@ public class Canvas { public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) { throwIfCannotDraw(bitmap); native_drawBitmap(mNativeCanvasWrapper, bitmap.ni(), left, top, - paint != null ? paint.mNativePaint : 0, mDensity, mScreenDensity, bitmap.mDensity); + paint != null ? paint.getNativeInstance() : 0, mDensity, mScreenDensity, bitmap.mDensity); } /** @@ -1367,7 +1371,7 @@ public class Canvas { throw new NullPointerException(); } throwIfCannotDraw(bitmap); - final long nativePaint = paint == null ? 0 : paint.mNativePaint; + final long nativePaint = paint == null ? 0 : paint.getNativeInstance(); float left, top, right, bottom; if (src == null) { @@ -1414,7 +1418,7 @@ public class Canvas { throw new NullPointerException(); } throwIfCannotDraw(bitmap); - final long nativePaint = paint == null ? 0 : paint.mNativePaint; + final long nativePaint = paint == null ? 0 : paint.getNativeInstance(); int left, top, right, bottom; if (src == null) { @@ -1482,7 +1486,7 @@ public class Canvas { } // punch down to native for the actual draw native_drawBitmap(mNativeCanvasWrapper, colors, offset, stride, x, y, width, height, hasAlpha, - paint != null ? paint.mNativePaint : 0); + paint != null ? paint.getNativeInstance() : 0); } /** @@ -1510,7 +1514,7 @@ public class Canvas { */ public void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint) { nativeDrawBitmapMatrix(mNativeCanvasWrapper, bitmap.ni(), matrix.ni(), - paint != null ? paint.mNativePaint : 0); + paint != null ? paint.getNativeInstance() : 0); } /** @@ -1566,7 +1570,7 @@ public class Canvas { } nativeDrawBitmapMesh(mNativeCanvasWrapper, bitmap.ni(), meshWidth, meshHeight, verts, vertOffset, colors, colorOffset, - paint != null ? paint.mNativePaint : 0); + paint != null ? paint.getNativeInstance() : 0); } public enum VertexMode { @@ -1619,6 +1623,9 @@ public class Canvas { int colorOffset, @Nullable short[] indices, int indexOffset, int indexCount, @NonNull Paint paint) { checkRange(verts.length, vertOffset, vertexCount); + if (isHardwareAccelerated()) { + return; + } if (texs != null) { checkRange(texs.length, texOffset, vertexCount); } @@ -1630,7 +1637,7 @@ public class Canvas { } nativeDrawVertices(mNativeCanvasWrapper, mode.nativeInt, vertexCount, verts, vertOffset, texs, texOffset, colors, colorOffset, - indices, indexOffset, indexCount, paint.mNativePaint); + indices, indexOffset, indexCount, paint.getNativeInstance()); } /** @@ -1639,7 +1646,7 @@ public class Canvas { * * @param text The text to be drawn * @param x The x-coordinate of the origin of the text being drawn - * @param y The y-coordinate of the origin of the text being drawn + * @param y The y-coordinate of the baseline of the text being drawn * @param paint The paint used for the text (e.g. color, size, style) */ public void drawText(@NonNull char[] text, int index, int count, float x, float y, @@ -1649,7 +1656,7 @@ public class Canvas { throw new IndexOutOfBoundsException(); } native_drawText(mNativeCanvasWrapper, text, index, count, x, y, paint.mBidiFlags, - paint.mNativePaint, paint.mNativeTypeface); + paint.getNativeInstance(), paint.mNativeTypeface); } /** @@ -1658,12 +1665,12 @@ public class Canvas { * * @param text The text to be drawn * @param x The x-coordinate of the origin of the text being drawn - * @param y The y-coordinate of the origin of the text being drawn + * @param y The y-coordinate of the baseline of the text being drawn * @param paint The paint used for the text (e.g. color, size, style) */ public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) { native_drawText(mNativeCanvasWrapper, text, 0, text.length(), x, y, paint.mBidiFlags, - paint.mNativePaint, paint.mNativeTypeface); + paint.getNativeInstance(), paint.mNativeTypeface); } /** @@ -1674,7 +1681,7 @@ public class Canvas { * @param start The index of the first character in text to draw * @param end (end - 1) is the index of the last character in text to draw * @param x The x-coordinate of the origin of the text being drawn - * @param y The y-coordinate of the origin of the text being drawn + * @param y The y-coordinate of the baseline of the text being drawn * @param paint The paint used for the text (e.g. color, size, style) */ public void drawText(@NonNull String text, int start, int end, float x, float y, @@ -1683,7 +1690,7 @@ public class Canvas { throw new IndexOutOfBoundsException(); } native_drawText(mNativeCanvasWrapper, text, start, end, x, y, paint.mBidiFlags, - paint.mNativePaint, paint.mNativeTypeface); + paint.getNativeInstance(), paint.mNativeTypeface); } /** @@ -1707,7 +1714,7 @@ public class Canvas { if (text instanceof String || text instanceof SpannedString || text instanceof SpannableString) { native_drawText(mNativeCanvasWrapper, text.toString(), start, end, x, y, - paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface); + paint.mBidiFlags, paint.getNativeInstance(), paint.mNativeTypeface); } else if (text instanceof GraphicsOperations) { ((GraphicsOperations) text).drawText(this, start, end, x, y, paint); @@ -1715,7 +1722,7 @@ public class Canvas { char[] buf = TemporaryBuffer.obtain(end - start); TextUtils.getChars(text, start, end, buf, 0); native_drawText(mNativeCanvasWrapper, buf, 0, end - start, x, y, - paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface); + paint.mBidiFlags, paint.getNativeInstance(), paint.mNativeTypeface); TemporaryBuffer.recycle(buf); } } @@ -1754,7 +1761,7 @@ public class Canvas { } native_drawTextRun(mNativeCanvasWrapper, text, index, count, - contextIndex, contextCount, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface); + contextIndex, contextCount, x, y, isRtl, paint.getNativeInstance(), paint.mNativeTypeface); } /** @@ -1790,7 +1797,7 @@ public class Canvas { if (text instanceof String || text instanceof SpannedString || text instanceof SpannableString) { native_drawTextRun(mNativeCanvasWrapper, text.toString(), start, end, - contextStart, contextEnd, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface); + contextStart, contextEnd, x, y, isRtl, paint.getNativeInstance(), paint.mNativeTypeface); } else if (text instanceof GraphicsOperations) { ((GraphicsOperations) text).drawTextRun(this, start, end, contextStart, contextEnd, x, y, isRtl, paint); @@ -1800,7 +1807,7 @@ public class Canvas { char[] buf = TemporaryBuffer.obtain(contextLen); TextUtils.getChars(text, contextStart, contextEnd, buf, 0); native_drawTextRun(mNativeCanvasWrapper, buf, start - contextStart, len, - 0, contextLen, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface); + 0, contextLen, x, y, isRtl, paint.getNativeInstance(), paint.mNativeTypeface); TemporaryBuffer.recycle(buf); } } @@ -1868,7 +1875,7 @@ public class Canvas { } native_drawTextOnPath(mNativeCanvasWrapper, text, index, count, path.ni(), hOffset, vOffset, - paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface); + paint.mBidiFlags, paint.getNativeInstance(), paint.mNativeTypeface); } /** @@ -1888,7 +1895,7 @@ public class Canvas { float vOffset, @NonNull Paint paint) { if (text.length() > 0) { native_drawTextOnPath(mNativeCanvasWrapper, text, path.ni(), hOffset, vOffset, - paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface); + paint.mBidiFlags, paint.getNativeInstance(), paint.mNativeTypeface); } } diff --git a/graphics/java/android/graphics/CanvasProperty.java b/graphics/java/android/graphics/CanvasProperty.java index be86060..ea3886c 100644 --- a/graphics/java/android/graphics/CanvasProperty.java +++ b/graphics/java/android/graphics/CanvasProperty.java @@ -31,7 +31,7 @@ public final class CanvasProperty<T> { } public static CanvasProperty<Paint> createPaint(Paint initialValue) { - return new CanvasProperty<Paint>(nCreatePaint(initialValue.mNativePaint)); + return new CanvasProperty<Paint>(nCreatePaint(initialValue.getNativeInstance())); } private CanvasProperty(long nativeContainer) { diff --git a/graphics/java/android/graphics/DrawFilter.java b/graphics/java/android/graphics/DrawFilter.java index ed38f37..aaefce9 100644 --- a/graphics/java/android/graphics/DrawFilter.java +++ b/graphics/java/android/graphics/DrawFilter.java @@ -24,8 +24,11 @@ package android.graphics; */ public class DrawFilter { - // this is set by subclasses, but don't make it public - /* package */ long mNativeInt; // pointer to native object + /** + * this is set by subclasses + * @hide + */ + public long mNativeInt; protected void finalize() throws Throwable { try { diff --git a/graphics/java/android/graphics/LayerRasterizer.java b/graphics/java/android/graphics/LayerRasterizer.java index e7a24a4..b692ecf 100644 --- a/graphics/java/android/graphics/LayerRasterizer.java +++ b/graphics/java/android/graphics/LayerRasterizer.java @@ -28,11 +28,11 @@ public class LayerRasterizer extends Rasterizer { object itself, so it may be reused without danger of side-effects. */ public void addLayer(Paint paint, float dx, float dy) { - nativeAddLayer(native_instance, paint.mNativePaint, dx, dy); + nativeAddLayer(native_instance, paint.getNativeInstance(), dx, dy); } public void addLayer(Paint paint) { - nativeAddLayer(native_instance, paint.mNativePaint, 0, 0); + nativeAddLayer(native_instance, paint.getNativeInstance(), 0, 0); } private static native long nativeConstructor(); diff --git a/graphics/java/android/graphics/Movie.java b/graphics/java/android/graphics/Movie.java index b0a4553..ecb4255 100644 --- a/graphics/java/android/graphics/Movie.java +++ b/graphics/java/android/graphics/Movie.java @@ -35,12 +35,17 @@ public class Movie { public native boolean isOpaque(); public native int duration(); - public native boolean setTime(int relativeMilliseconds); + public native boolean setTime(int relativeMilliseconds); + + private native void nDraw(long nativeCanvas, float x, float y, long paintHandle); + + public void draw(Canvas canvas, float x, float y, Paint paint) { + nDraw(canvas.getNativeCanvasWrapper(), x, y, + paint != null ? paint.getNativeInstance() : 0); + } - public native void draw(Canvas canvas, float x, float y, Paint paint); - public void draw(Canvas canvas, float x, float y) { - draw(canvas, x, y, null); + nDraw(canvas.getNativeCanvasWrapper(), x, y, 0); } public static Movie decodeStream(InputStream is) { diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java index 6f42046..ebc86aa 100644 --- a/graphics/java/android/graphics/NinePatch.java +++ b/graphics/java/android/graphics/NinePatch.java @@ -200,12 +200,12 @@ public class NinePatch { void drawSoftware(Canvas canvas, RectF location, Paint paint) { nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.ni(), mNativeChunk, - paint != null ? paint.mNativePaint : 0, canvas.mDensity, mBitmap.mDensity); + paint != null ? paint.getNativeInstance() : 0, canvas.mDensity, mBitmap.mDensity); } void drawSoftware(Canvas canvas, Rect location, Paint paint) { nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.ni(), mNativeChunk, - paint != null ? paint.mNativePaint : 0, canvas.mDensity, mBitmap.mDensity); + paint != null ? paint.getNativeInstance() : 0, canvas.mDensity, mBitmap.mDensity); } /** diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 652fe64..91c8dba 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -29,10 +29,9 @@ import java.util.Locale; */ public class Paint { - /** - * @hide - */ - public long mNativePaint; + private long mNativePaint; + private long mNativeShader = 0; + /** * @hide */ @@ -445,7 +444,7 @@ public class Paint { * new paint. */ public Paint(Paint paint) { - mNativePaint = native_initWithPaint(paint.mNativePaint); + mNativePaint = native_initWithPaint(paint.getNativeInstance()); setClassVariablesFrom(paint); } @@ -464,6 +463,7 @@ public class Paint { mPathEffect = null; mRasterizer = null; mShader = null; + mNativeShader = 0; mTypeface = null; mNativeTypeface = 0; mXfermode = null; @@ -500,11 +500,8 @@ public class Paint { mMaskFilter = paint.mMaskFilter; mPathEffect = paint.mPathEffect; mRasterizer = paint.mRasterizer; - if (paint.mShader != null) { - mShader = paint.mShader.copy(); - } else { - mShader = null; - } + mShader = paint.mShader; + mNativeShader = paint.mNativeShader; mTypeface = paint.mTypeface; mNativeTypeface = paint.mNativeTypeface; mXfermode = paint.mXfermode; @@ -531,6 +528,20 @@ public class Paint { } /** + * Return the pointer to the native object while ensuring that any + * mutable objects that are attached to the paint are also up-to-date. + * + * @hide + */ + public long getNativeInstance() { + if (mShader != null && mShader.getNativeInstance() != mNativeShader) { + mNativeShader = mShader.getNativeInstance(); + native_setShader(mNativePaint, mNativeShader); + } + return mNativePaint; + } + + /** * Return the bidi flags on the paint. * * @return the bidi flags on the paint @@ -920,10 +931,7 @@ public class Paint { * @return shader */ public Shader setShader(Shader shader) { - long shaderNative = 0; - if (shader != null) - shaderNative = shader.getNativeInstance(); - native_setShader(mNativePaint, shaderNative); + // Defer setting the shader natively until getNativeInstance() is called mShader = shader; return shader; } diff --git a/graphics/java/android/graphics/PaintFlagsDrawFilter.java b/graphics/java/android/graphics/PaintFlagsDrawFilter.java index 65a6218..2326611 100644 --- a/graphics/java/android/graphics/PaintFlagsDrawFilter.java +++ b/graphics/java/android/graphics/PaintFlagsDrawFilter.java @@ -17,11 +17,6 @@ package android.graphics; public class PaintFlagsDrawFilter extends DrawFilter { - /** @hide **/ - public final int clearBits; - /** @hide **/ - public final int setBits; - /** * Subclass of DrawFilter that affects every paint by first clearing * the specified clearBits in the paint's flags, and then setting the @@ -31,8 +26,6 @@ public class PaintFlagsDrawFilter extends DrawFilter { * @param setBits These bits will be set in the paint's flags */ public PaintFlagsDrawFilter(int clearBits, int setBits) { - this.clearBits = clearBits; - this.setBits = setBits; // our native constructor can return 0, if the specified bits // are effectively a no-op mNativeInt = nativeConstructor(clearBits, setBits); diff --git a/graphics/java/android/graphics/Picture.java b/graphics/java/android/graphics/Picture.java index fa9af2a..39272b9 100644 --- a/graphics/java/android/graphics/Picture.java +++ b/graphics/java/android/graphics/Picture.java @@ -122,11 +122,6 @@ public class Picture { * @param canvas The picture is drawn to this canvas */ public void draw(Canvas canvas) { - if (canvas.isHardwareAccelerated()) { - throw new IllegalArgumentException( - "Picture playback is only supported on software canvas."); - } - if (mRecordingCanvas != null) { endRecording(); } diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java index 6934955..a96d2cb 100644 --- a/graphics/java/android/graphics/Shader.java +++ b/graphics/java/android/graphics/Shader.java @@ -82,7 +82,8 @@ public class Shader { */ public void setLocalMatrix(Matrix localM) { mLocalMatrix = localM; - nativeSetLocalMatrix(native_instance, localM == null ? 0 : localM.native_instance); + native_instance = nativeSetLocalMatrix(native_instance, + localM == null ? 0 : localM.native_instance); } protected void finalize() throws Throwable { @@ -120,5 +121,5 @@ public class Shader { } private static native void nativeDestructor(long native_shader); - private static native void nativeSetLocalMatrix(long native_shader, long matrix_instance); + private static native long nativeSetLocalMatrix(long native_shader, long matrix_instance); } diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java index 9be296a..945ae2e 100644 --- a/graphics/java/android/graphics/drawable/BitmapDrawable.java +++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java @@ -357,6 +357,11 @@ public class BitmapDrawable extends Drawable { invalidateSelf(); } + @Override + public boolean getDither() { + return mBitmapState.mPaint.isDither(); + } + /** * Indicates the repeat behavior of this drawable on the X axis. * @@ -705,8 +710,8 @@ public class BitmapDrawable extends Drawable { @Override public boolean isStateful() { - final BitmapState s = mBitmapState; - return super.isStateful() || (s.mTint != null && s.mTint.isStateful()); + return (mBitmapState.mTint != null && mBitmapState.mTint.isStateful()) + || super.isStateful(); } @Override @@ -718,6 +723,9 @@ public class BitmapDrawable extends Drawable { updateStateFromTypedArray(a); verifyState(a); a.recycle(); + + // Update local properties. + updateLocalState(r); } /** @@ -800,9 +808,6 @@ public class BitmapDrawable extends Drawable { if (tileModeY != TILE_MODE_UNDEFINED) { setTileModeY(parseTileMode(tileModeY)); } - - // Update local properties. - initializeWithState(state, r); } @Override @@ -810,18 +815,28 @@ public class BitmapDrawable extends Drawable { super.applyTheme(t); final BitmapState state = mBitmapState; - if (state == null || state.mThemeAttrs == null) { + if (state == null) { return; } - final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.BitmapDrawable); - try { - updateStateFromTypedArray(a); - } catch (XmlPullParserException e) { - throw new RuntimeException(e); - } finally { - a.recycle(); + if (state.mThemeAttrs != null) { + final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.BitmapDrawable); + try { + updateStateFromTypedArray(a); + } catch (XmlPullParserException e) { + throw new RuntimeException(e); + } finally { + a.recycle(); + } + } + + // Apply theme to contained color state list. + if (state.mTint != null && state.mTint.canApplyTheme()) { + state.mTint.applyTheme(t); } + + // Update local properties. + updateLocalState(t.getResources()); } private static Shader.TileMode parseTileMode(int tileMode) { @@ -839,7 +854,7 @@ public class BitmapDrawable extends Drawable { @Override public boolean canApplyTheme() { - return mBitmapState != null && mBitmapState.mThemeAttrs != null; + return mBitmapState != null && mBitmapState.canApplyTheme(); } @Override @@ -910,7 +925,7 @@ public class BitmapDrawable extends Drawable { @Override public boolean canApplyTheme() { - return mThemeAttrs != null; + return mThemeAttrs != null || mTint != null && mTint.canApplyTheme(); } @Override @@ -944,7 +959,7 @@ public class BitmapDrawable extends Drawable { private BitmapDrawable(BitmapState state, Resources res) { mBitmapState = state; - initializeWithState(mBitmapState, res); + updateLocalState(res); } /** @@ -952,14 +967,14 @@ public class BitmapDrawable extends Drawable { * after significant state changes, e.g. from the One True Constructor and * after inflating or applying a theme. */ - private void initializeWithState(BitmapState state, Resources res) { + private void updateLocalState(Resources res) { if (res != null) { mTargetDensity = res.getDisplayMetrics().densityDpi; } else { - mTargetDensity = state.mTargetDensity; + mTargetDensity = mBitmapState.mTargetDensity; } - mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); + mTintFilter = updateTintFilter(mTintFilter, mBitmapState.mTint, mBitmapState.mTintMode); computeBitmapSize(); } } diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java index e3b50ea..85e02b7 100644 --- a/graphics/java/android/graphics/drawable/ColorDrawable.java +++ b/graphics/java/android/graphics/drawable/ColorDrawable.java @@ -70,7 +70,7 @@ public class ColorDrawable extends Drawable { @Override public int getChangingConfigurations() { - return super.getChangingConfigurations() | mColorState.mChangingConfigurations; + return super.getChangingConfigurations() | mColorState.getChangingConfigurations(); } /** @@ -233,6 +233,8 @@ public class ColorDrawable extends Drawable { final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ColorDrawable); updateStateFromTypedArray(a); a.recycle(); + + updateLocalState(r); } /** @@ -261,13 +263,21 @@ public class ColorDrawable extends Drawable { super.applyTheme(t); final ColorState state = mColorState; - if (state == null || state.mThemeAttrs == null) { + if (state == null) { return; } - final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ColorDrawable); - updateStateFromTypedArray(a); - a.recycle(); + if (state.mThemeAttrs != null) { + final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ColorDrawable); + updateStateFromTypedArray(a); + a.recycle(); + } + + if (state.mTint != null && state.mTint.canApplyTheme()) { + state.mTint.applyTheme(t); + } + + updateLocalState(t.getResources()); } @Override @@ -299,17 +309,18 @@ public class ColorDrawable extends Drawable { @Override public boolean canApplyTheme() { - return mThemeAttrs != null; + return mThemeAttrs != null + || (mTint != null && mTint.canApplyTheme()); } @Override public Drawable newDrawable() { - return new ColorDrawable(this); + return new ColorDrawable(this, null); } @Override public Drawable newDrawable(Resources res) { - return new ColorDrawable(this); + return new ColorDrawable(this, res); } @Override @@ -318,8 +329,18 @@ public class ColorDrawable extends Drawable { } } - private ColorDrawable(ColorState state) { + private ColorDrawable(ColorState state, Resources res) { mColorState = state; - mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); + + updateLocalState(res); + } + + /** + * Initializes local dynamic properties from state. This should be called + * after significant state changes, e.g. from the One True Constructor and + * after inflating or applying a theme. + */ + private void updateLocalState(Resources r) { + mTintFilter = updateTintFilter(mTintFilter, mColorState.mTint, mColorState.mTintMode); } } diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index 0e38cc0..c9d7869 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -39,6 +39,7 @@ import android.graphics.Xfermode; import android.os.Trace; import android.util.AttributeSet; import android.util.DisplayMetrics; +import android.util.IntProperty; import android.util.StateSet; import android.util.TypedValue; import android.util.Xml; @@ -274,6 +275,14 @@ public abstract class Drawable { public void setDither(boolean dither) {} /** + * @return whether this drawable dither its colors + * @see #setDither(boolean) + */ + public boolean getDither() { + return false; + } + + /** * Set to true to have the drawable filter its bitmap when scaled or rotated * (for drawables that use bitmaps). If the drawable does not use bitmaps, * this call is ignored. This can improve the look when scaled or rotated, @@ -282,6 +291,14 @@ public abstract class Drawable { public void setFilterBitmap(boolean filter) {} /** + * @return whether this drawable filters its bitmap + * @see #setFilterBitmap(boolean) + */ + public boolean getFilterBitmap() { + return false; + } + + /** * Implement this interface if you want to create an animated drawable that * extends {@link android.graphics.drawable.Drawable Drawable}. * Upon retrieving a drawable, use @@ -1335,5 +1352,20 @@ public abstract class Drawable { default: return defaultMode; } } + + /** @hide */ + public static final IntProperty<Drawable> ALPHA = new IntProperty<Drawable>("alpha") { + @Override + public void setValue(Drawable object, int value) { + object.mutate(); + object.setAlpha(value); + object.invalidateSelf(); + } + + @Override + public Integer get(Drawable object) { + return object.getAlpha(); + } + }; } diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index 39ef10c..557f563 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -167,6 +167,11 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } @Override + public boolean getDither() { + return mDrawableContainerState.mDither; + } + + @Override public void setColorFilter(ColorFilter cf) { mDrawableContainerState.mHasColorFilter = (cf != null); diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java index 72707e6..cc2de22 100644 --- a/graphics/java/android/graphics/drawable/GradientDrawable.java +++ b/graphics/java/android/graphics/drawable/GradientDrawable.java @@ -143,7 +143,7 @@ public class GradientDrawable extends Drawable { private final RectF mRect = new RectF(); private Paint mLayerPaint; // internal, used if we use saveLayer() - private boolean mGradientIsDirty; // internal state + private boolean mGradientIsDirty; private boolean mMutated; private Path mRingPath; private boolean mPathIsDirty = true; @@ -174,7 +174,7 @@ public class GradientDrawable extends Drawable { } public GradientDrawable() { - this(new GradientState(Orientation.TOP_BOTTOM, null)); + this(new GradientState(Orientation.TOP_BOTTOM, null), null); } /** @@ -182,7 +182,7 @@ public class GradientDrawable extends Drawable { * of colors for the gradient. */ public GradientDrawable(Orientation orientation, int[] colors) { - this(new GradientState(orientation, colors)); + this(new GradientState(orientation, colors), null); } @Override @@ -822,6 +822,11 @@ public class GradientDrawable extends Drawable { } @Override + public boolean getDither() { + return mGradientState.mDither; + } + + @Override public ColorFilter getColorFilter() { return mColorFilter; } @@ -1018,7 +1023,7 @@ public class GradientDrawable extends Drawable { inflateChildElements(r, parser, attrs, theme); - mGradientState.computeOpacity(); + updateLocalState(r); } @Override @@ -1037,9 +1042,21 @@ public class GradientDrawable extends Drawable { a.recycle(); } + if (state.mTint != null && state.mTint.canApplyTheme()) { + state.mTint.applyTheme(t); + } + + if (state.mColorStateList != null && state.mColorStateList.canApplyTheme()) { + state.mColorStateList.applyTheme(t); + } + + if (state.mStrokeColorStateList != null && state.mStrokeColorStateList.canApplyTheme()) { + state.mStrokeColorStateList.applyTheme(t); + } + applyThemeChildElements(t); - state.computeOpacity(); + updateLocalState(t.getResources()); } /** @@ -1087,8 +1104,6 @@ public class GradientDrawable extends Drawable { if (tint != null) { state.mTint = tint; } - - mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); } @Override @@ -1516,7 +1531,7 @@ public class GradientDrawable extends Drawable { public Drawable mutate() { if (!mMutated && super.mutate() == this) { mGradientState = new GradientState(mGradientState); - initializeWithState(mGradientState); + updateLocalState(null); mMutated = true; } return this; @@ -1577,7 +1592,7 @@ public class GradientDrawable extends Drawable { int[] mAttrCorners; int[] mAttrPadding; - GradientState(Orientation orientation, int[] colors) { + public GradientState(Orientation orientation, int[] colors) { mOrientation = orientation; setColors(colors); } @@ -1634,19 +1649,24 @@ public class GradientDrawable extends Drawable { @Override public boolean canApplyTheme() { - return mThemeAttrs != null || mAttrSize != null || mAttrGradient != null - || mAttrSolid != null || mAttrStroke != null || mAttrCorners != null - || mAttrPadding != null || super.canApplyTheme(); + return mThemeAttrs != null + || mAttrSize != null || mAttrGradient != null + || mAttrSolid != null || mAttrStroke != null + || mAttrCorners != null || mAttrPadding != null + || (mTint != null && mTint.canApplyTheme()) + || (mStrokeColorStateList != null && mStrokeColorStateList.canApplyTheme()) + || (mColorStateList != null && mColorStateList.canApplyTheme()) + || super.canApplyTheme(); } @Override public Drawable newDrawable() { - return new GradientDrawable(this); + return new GradientDrawable(this, null); } @Override public Drawable newDrawable(Resources res) { - return new GradientDrawable(this); + return new GradientDrawable(this, res); } @Override @@ -1751,16 +1771,15 @@ public class GradientDrawable extends Drawable { * * @param state Constant state from which the drawable inherits */ - private GradientDrawable(GradientState state) { + private GradientDrawable(GradientState state, Resources res) { mGradientState = state; - initializeWithState(mGradientState); - - mGradientIsDirty = true; - mMutated = false; + updateLocalState(res); } - private void initializeWithState(GradientState state) { + private void updateLocalState(Resources res) { + final GradientState state = mGradientState; + if (state.mColorStateList != null) { final int[] currentState = getState(); final int stateColor = state.mColorStateList.getColorForState(currentState, 0); @@ -1797,5 +1816,8 @@ public class GradientDrawable extends Drawable { } mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); + mGradientIsDirty = true; + + state.computeOpacity(); } } diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java index 8b70a08..50a6df4 100644 --- a/graphics/java/android/graphics/drawable/InsetDrawable.java +++ b/graphics/java/android/graphics/drawable/InsetDrawable.java @@ -34,7 +34,6 @@ import android.graphics.Insets; import android.graphics.Outline; import android.graphics.PixelFormat; import android.graphics.PorterDuff.Mode; -import android.graphics.drawable.Drawable.ConstantState; import android.graphics.Rect; import android.util.AttributeSet; @@ -60,28 +59,49 @@ import java.util.Collection; public class InsetDrawable extends Drawable implements Drawable.Callback { private final Rect mTmpRect = new Rect(); - private final InsetState mState; + private InsetState mState; + private Drawable mDrawable; private boolean mMutated; - /*package*/ InsetDrawable() { - this(null, null); + /** + * No-arg constructor used by drawable inflation. + */ + InsetDrawable() { + this(new InsetState(), null); } + /** + * Creates a new inset drawable with the specified inset. + * + * @param drawable The drawable to inset. + * @param inset Inset in pixels around the drawable. + */ public InsetDrawable(Drawable drawable, int inset) { this(drawable, inset, inset, inset, inset); } - public InsetDrawable(Drawable drawable, int insetLeft, int insetTop, - int insetRight, int insetBottom) { - this(null, null); + /** + * Creates a new inset drawable with the specified insets. + * + * @param drawable The drawable to inset. + * @param insetLeft Left inset in pixels. + * @param insetTop Top inset in pixels. + * @param insetRight Right inset in pixels. + * @param insetBottom Bottom inset in pixels. + */ + public InsetDrawable(Drawable drawable, int insetLeft, int insetTop,int insetRight, + int insetBottom) { + this(new InsetState(), null); - mState.mDrawable = drawable; + mState.mDrawableState = drawable == null ? null : drawable.getConstantState(); mState.mInsetLeft = insetLeft; mState.mInsetTop = insetTop; mState.mInsetRight = insetRight; mState.mInsetBottom = insetBottom; + mDrawable = drawable; + if (drawable != null) { drawable.setCallback(this); } @@ -93,38 +113,53 @@ public class InsetDrawable extends Drawable implements Drawable.Callback { final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.InsetDrawable); super.inflateWithAttributes(r, parser, a, R.styleable.InsetDrawable_visible); - // Reset mDrawable to preserve old multiple-inflate behavior. This is - // silly, but we have CTS tests that rely on it. - mState.mDrawable = null; - updateStateFromTypedArray(a); inflateChildElements(r, parser, attrs, theme); verifyRequiredAttributes(a); a.recycle(); } + private void setDrawable(Drawable dr) { + if (mDrawable != null) { + mDrawable.setCallback(null); + } + + mDrawable = dr; + + if (dr != null) { + dr.setCallback(this); + dr.setVisible(isVisible(), true); + dr.setState(getState()); + dr.setLevel(getLevel()); + dr.setBounds(getBounds()); + dr.setLayoutDirection(getLayoutDirection()); + } + } + private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) throws XmlPullParserException, IOException { // Load inner XML elements. - if (mState.mDrawable == null) { + if (mDrawable == null) { int type; while ((type=parser.next()) == XmlPullParser.TEXT) { } if (type != XmlPullParser.START_TAG) { - throw new XmlPullParserException( - parser.getPositionDescription() - + ": <inset> tag requires a 'drawable' attribute or " - + "child tag defining a drawable"); + throw new XmlPullParserException(parser.getPositionDescription() + + ": <inset> tag requires a 'drawable' attribute or " + + "child tag defining a drawable"); } + final Drawable dr = Drawable.createFromXmlInner(r, parser, attrs, theme); - mState.mDrawable = dr; - dr.setCallback(this); + if (dr != null) { + mState.mDrawableState = dr.getConstantState(); + setDrawable(dr); + } } } private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException { // If we're not waiting on a theme, verify required attributes. - if (mState.mDrawable == null && (mState.mThemeAttrs == null + if (mDrawable == null && (mState.mThemeAttrs == null || mState.mThemeAttrs[R.styleable.InsetDrawable_drawable] == 0)) { throw new XmlPullParserException(a.getPositionDescription() + ": <inset> tag requires a 'drawable' attribute or " @@ -148,8 +183,8 @@ public class InsetDrawable extends Drawable implements Drawable.Callback { case R.styleable.InsetDrawable_drawable: final Drawable dr = a.getDrawable(attr); if (dr != null) { - state.mDrawable = dr; - dr.setCallback(this); + mState.mDrawableState = dr.getConstantState(); + setDrawable(dr); } break; case R.styleable.InsetDrawable_inset: @@ -198,8 +233,8 @@ public class InsetDrawable extends Drawable implements Drawable.Callback { } } - if (state.mDrawable != null && state.mDrawable.canApplyTheme()) { - state.mDrawable.applyTheme(t); + if (mDrawable != null && mDrawable.canApplyTheme()) { + mDrawable.applyTheme(t); } } @@ -234,27 +269,27 @@ public class InsetDrawable extends Drawable implements Drawable.Callback { @Override public void draw(Canvas canvas) { - mState.mDrawable.draw(canvas); + mDrawable.draw(canvas); } @Override public int getChangingConfigurations() { return super.getChangingConfigurations() | mState.mChangingConfigurations - | mState.mDrawable.getChangingConfigurations(); + | mDrawable.getChangingConfigurations(); } @Override public boolean getPadding(Rect padding) { - boolean pad = mState.mDrawable.getPadding(padding); + final boolean pad = mDrawable.getPadding(padding); padding.left += mState.mInsetLeft; padding.right += mState.mInsetRight; padding.top += mState.mInsetTop; padding.bottom += mState.mInsetBottom; - return pad || (mState.mInsetLeft | mState.mInsetRight | - mState.mInsetTop | mState.mInsetBottom) != 0; + return pad || (mState.mInsetLeft | mState.mInsetRight + | mState.mInsetTop | mState.mInsetBottom) != 0; } /** @hide */ @@ -269,61 +304,61 @@ public class InsetDrawable extends Drawable implements Drawable.Callback { @Override public void setHotspot(float x, float y) { - mState.mDrawable.setHotspot(x, y); + mDrawable.setHotspot(x, y); } @Override public void setHotspotBounds(int left, int top, int right, int bottom) { - mState.mDrawable.setHotspotBounds(left, top, right, bottom); + mDrawable.setHotspotBounds(left, top, right, bottom); } /** @hide */ @Override public void getHotspotBounds(Rect outRect) { - mState.mDrawable.getHotspotBounds(outRect); + mDrawable.getHotspotBounds(outRect); } @Override public boolean setVisible(boolean visible, boolean restart) { - mState.mDrawable.setVisible(visible, restart); + mDrawable.setVisible(visible, restart); return super.setVisible(visible, restart); } @Override public void setAlpha(int alpha) { - mState.mDrawable.setAlpha(alpha); + mDrawable.setAlpha(alpha); } @Override public int getAlpha() { - return mState.mDrawable.getAlpha(); + return mDrawable.getAlpha(); } @Override public void setColorFilter(ColorFilter cf) { - mState.mDrawable.setColorFilter(cf); + mDrawable.setColorFilter(cf); } @Override public void setTintList(ColorStateList tint) { - mState.mDrawable.setTintList(tint); + mDrawable.setTintList(tint); } @Override public void setTintMode(Mode tintMode) { - mState.mDrawable.setTintMode(tintMode); + mDrawable.setTintMode(tintMode); } /** {@hide} */ @Override public void setLayoutDirection(int layoutDirection) { - mState.mDrawable.setLayoutDirection(layoutDirection); + mDrawable.setLayoutDirection(layoutDirection); } @Override public int getOpacity() { final InsetState state = mState; - final int opacity = state.mDrawable.getOpacity(); + final int opacity = mDrawable.getOpacity(); if (opacity == PixelFormat.OPAQUE && (state.mInsetLeft > 0 || state.mInsetTop > 0 || state.mInsetRight > 0 || state.mInsetBottom > 0)) { return PixelFormat.TRANSLUCENT; @@ -333,19 +368,19 @@ public class InsetDrawable extends Drawable implements Drawable.Callback { @Override public boolean isStateful() { - return mState.mDrawable.isStateful(); + return mDrawable.isStateful(); } @Override protected boolean onStateChange(int[] state) { - boolean changed = mState.mDrawable.setState(state); + final boolean changed = mDrawable.setState(state); onBoundsChange(getBounds()); return changed; } @Override protected boolean onLevelChange(int level) { - return mState.mDrawable.setLevel(level); + return mDrawable.setLevel(level); } @Override @@ -358,24 +393,22 @@ public class InsetDrawable extends Drawable implements Drawable.Callback { r.right -= mState.mInsetRight; r.bottom -= mState.mInsetBottom; - mState.mDrawable.setBounds(r.left, r.top, r.right, r.bottom); + mDrawable.setBounds(r.left, r.top, r.right, r.bottom); } @Override public int getIntrinsicWidth() { - return mState.mDrawable.getIntrinsicWidth() - + mState.mInsetLeft + mState.mInsetRight; + return mDrawable.getIntrinsicWidth() + mState.mInsetLeft + mState.mInsetRight; } @Override public int getIntrinsicHeight() { - return mState.mDrawable.getIntrinsicHeight() - + mState.mInsetTop + mState.mInsetBottom; + return mDrawable.getIntrinsicHeight() + mState.mInsetTop + mState.mInsetBottom; } @Override public void getOutline(@NonNull Outline outline) { - mState.mDrawable.getOutline(outline); + mDrawable.getOutline(outline); } @Override @@ -390,7 +423,9 @@ public class InsetDrawable extends Drawable implements Drawable.Callback { @Override public Drawable mutate() { if (!mMutated && super.mutate() == this) { - mState.mDrawable.mutate(); + mState = new InsetState(mState); + mDrawable.mutate(); + mState.mDrawableState = mDrawable.getConstantState(); mMutated = true; } return this; @@ -401,7 +436,7 @@ public class InsetDrawable extends Drawable implements Drawable.Callback { */ public void clearMutated() { super.clearMutated(); - mState.mDrawable.clearMutated(); + mDrawable.clearMutated(); mMutated = false; } @@ -409,51 +444,53 @@ public class InsetDrawable extends Drawable implements Drawable.Callback { * Returns the drawable wrapped by this InsetDrawable. May be null. */ public Drawable getDrawable() { - return mState.mDrawable; + return mDrawable; } - final static class InsetState extends ConstantState { + private static final class InsetState extends ConstantState { int[] mThemeAttrs; int mChangingConfigurations; - Drawable mDrawable; + ConstantState mDrawableState; int mInsetLeft = 0; int mInsetTop = 0; int mInsetRight = 0; int mInsetBottom = 0; - private boolean mCheckedConstantState; - private boolean mCanConstantState; + public InsetState() { + // Empty constructor. + } - InsetState(InsetState orig, InsetDrawable owner, Resources res) { + public InsetState(InsetState orig) { if (orig != null) { mThemeAttrs = orig.mThemeAttrs; mChangingConfigurations = orig.mChangingConfigurations; - if (res != null) { - mDrawable = orig.mDrawable.getConstantState().newDrawable(res); - } else { - mDrawable = orig.mDrawable.getConstantState().newDrawable(); - } - mDrawable.setCallback(owner); - mDrawable.setLayoutDirection(orig.mDrawable.getLayoutDirection()); - mDrawable.setBounds(orig.mDrawable.getBounds()); - mDrawable.setLevel(orig.mDrawable.getLevel()); + mDrawableState = orig.mDrawableState; mInsetLeft = orig.mInsetLeft; mInsetTop = orig.mInsetTop; mInsetRight = orig.mInsetRight; mInsetBottom = orig.mInsetBottom; - mCheckedConstantState = mCanConstantState = true; } } @Override public boolean canApplyTheme() { - return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme()) + return mThemeAttrs != null + || (mDrawableState != null && mDrawableState.canApplyTheme()) || super.canApplyTheme(); } @Override + public int addAtlasableBitmaps(Collection<Bitmap> atlasList) { + final ConstantState state = mDrawableState; + if (state != null) { + return state.addAtlasableBitmaps(atlasList); + } + return 0; + } + + @Override public Drawable newDrawable() { return new InsetDrawable(this, null); } @@ -468,27 +505,31 @@ public class InsetDrawable extends Drawable implements Drawable.Callback { return mChangingConfigurations; } - boolean canConstantState() { - if (!mCheckedConstantState) { - mCanConstantState = mDrawable.getConstantState() != null; - mCheckedConstantState = true; - } - - return mCanConstantState; - } - - @Override - public int addAtlasableBitmaps(Collection<Bitmap> atlasList) { - final ConstantState state = mDrawable.getConstantState(); - if (state != null) { - return state.addAtlasableBitmaps(atlasList); - } - return 0; + public boolean canConstantState() { + return mDrawableState != null; } } + /** + * The one constructor to rule them all. This is called by all public + * constructors to set the state and initialize local properties. + */ private InsetDrawable(InsetState state, Resources res) { - mState = new InsetState(state, this, res); + mState = state; + + updateLocalState(res); + } + + /** + * Initializes local dynamic properties from state. This should be called + * after significant state changes, e.g. from the One True Constructor and + * after inflating or applying a theme. + */ + private void updateLocalState(Resources res) { + if (mState.mDrawableState != null) { + final Drawable dr = mState.mDrawableState.newDrawable(res); + setDrawable(dr); + } } } diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java index 4aa5f59..616aebd 100644 --- a/graphics/java/android/graphics/drawable/LayerDrawable.java +++ b/graphics/java/android/graphics/drawable/LayerDrawable.java @@ -29,6 +29,8 @@ import android.graphics.PixelFormat; import android.graphics.PorterDuff.Mode; import android.graphics.Rect; import android.util.AttributeSet; +import android.util.LayoutDirection; +import android.view.Gravity; import android.view.View; import com.android.internal.R; @@ -54,6 +56,11 @@ import java.util.Collection; * @attr ref android.R.styleable#LayerDrawableItem_top * @attr ref android.R.styleable#LayerDrawableItem_right * @attr ref android.R.styleable#LayerDrawableItem_bottom + * @attr ref android.R.styleable#LayerDrawableItem_start + * @attr ref android.R.styleable#LayerDrawableItem_end + * @attr ref android.R.styleable#LayerDrawableItem_width + * @attr ref android.R.styleable#LayerDrawableItem_height + * @attr ref android.R.styleable#LayerDrawableItem_gravity * @attr ref android.R.styleable#LayerDrawableItem_drawable * @attr ref android.R.styleable#LayerDrawableItem_id */ @@ -73,6 +80,9 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { */ public static final int PADDING_MODE_STACK = 1; + /** Value used for undefined start and end insets. */ + private static final int UNDEFINED_INSET = Integer.MIN_VALUE; + LayerState mLayerState; private int mOpacityOverride = PixelFormat.UNKNOWN; @@ -82,6 +92,8 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { private int[] mPaddingB; private final Rect mTmpRect = new Rect(); + private final Rect mTmpOutRect = new Rect(); + private final Rect mTmpContainer = new Rect(); private Rect mHotspotBounds; private boolean mMutated; @@ -231,6 +243,16 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { R.styleable.LayerDrawableItem_right, layer.mInsetR); layer.mInsetB = a.getDimensionPixelOffset( R.styleable.LayerDrawableItem_bottom, layer.mInsetB); + layer.mInsetS = a.getDimensionPixelOffset( + R.styleable.LayerDrawableItem_start, layer.mInsetS); + layer.mInsetE = a.getDimensionPixelOffset( + R.styleable.LayerDrawableItem_end, layer.mInsetE); + layer.mWidth = a.getDimensionPixelSize( + R.styleable.LayerDrawableItem_width, layer.mWidth); + layer.mHeight = a.getDimensionPixelSize( + R.styleable.LayerDrawableItem_height, layer.mHeight); + layer.mGravity = a.getInteger( + R.styleable.LayerDrawableItem_gravity, layer.mGravity); layer.mId = a.getResourceId(R.styleable.LayerDrawableItem_id, layer.mId); final Drawable dr = a.getDrawable(R.styleable.LayerDrawableItem_drawable); @@ -300,7 +322,13 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { return false; } - void addLayer(ChildDrawable layer) { + /** + * Adds a new layer at the end of list of layers and returns its index. + * + * @param layer The layer to add. + * @return The index of the layer. + */ + int addLayer(ChildDrawable layer) { final LayerState st = mLayerState; final int N = st.mChildren != null ? st.mChildren.length : 0; final int i = st.mNum; @@ -316,12 +344,13 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { st.mChildren[i] = layer; st.mNum++; st.invalidateCache(); + return i; } /** * Add a new layer to this drawable. The new layer is identified by an id. * - * @param layer The drawable to add as a layer. + * @param dr The drawable to add as a layer. * @param themeAttrs Theme attributes extracted from the layer. * @param id The id of the new layer. * @param left The left padding of the new layer. @@ -329,12 +358,11 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { * @param right The right padding of the new layer. * @param bottom The bottom padding of the new layer. */ - ChildDrawable addLayer(Drawable layer, int[] themeAttrs, int id, int left, int top, int right, - int bottom) { - final ChildDrawable childDrawable = new ChildDrawable(); + ChildDrawable addLayer(Drawable dr, int[] themeAttrs, int id, + int left, int top, int right, int bottom) { + final ChildDrawable childDrawable = createLayer(dr); childDrawable.mId = id; childDrawable.mThemeAttrs = themeAttrs; - childDrawable.mDrawable = layer; childDrawable.mDrawable.setAutoMirrored(isAutoMirrored()); childDrawable.mInsetL = left; childDrawable.mInsetT = top; @@ -343,12 +371,31 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { addLayer(childDrawable); - mLayerState.mChildrenChangingConfigurations |= layer.getChangingConfigurations(); - layer.setCallback(this); + mLayerState.mChildrenChangingConfigurations |= dr.getChangingConfigurations(); + dr.setCallback(this); return childDrawable; } + private ChildDrawable createLayer(Drawable dr) { + final ChildDrawable layer = new ChildDrawable(); + layer.mDrawable = dr; + return layer; + } + + /** + * Adds a new layer containing the specified {@code drawable} to the end of + * the layer list and returns its index. + * + * @param dr The drawable to add as a new layer. + * @return The index of the new layer. + */ + public int addLayer(Drawable dr) { + final ChildDrawable layer = createLayer(dr); + final int index = addLayer(layer); + return index; + } + /** * Looks for a layer with the given ID and returns its {@link Drawable}. * <p> @@ -373,45 +420,46 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { /** * Sets the ID of a layer. * - * @param index The index of the layer which will received the ID. - * @param id The ID to assign to the layer. + * @param index The index of the layer to modify, must be in the range + * {@code 0...getNumberOfLayers()-1}. + * @param id The id to assign to the layer. + * + * @see #getId(int) + * @attr ref android.R.styleable#LayerDrawableItem_id */ public void setId(int index, int id) { mLayerState.mChildren[index].mId = id; } /** - * Returns the number of layers contained within this. - * @return The number of layers. - */ - public int getNumberOfLayers() { - return mLayerState.mNum; - } - - /** - * Returns the drawable at the specified layer index. + * Returns the ID of the specified layer. * - * @param index The layer index of the drawable to retrieve. + * @param index The index of the layer, must be in the range + * {@code 0...getNumberOfLayers()-1}. + * @return The id of the layer or {@link android.view.View#NO_ID} if the + * layer has no id. * - * @return The {@link android.graphics.drawable.Drawable} at the specified layer index. + * @see #setId(int, int) + * @attr ref android.R.styleable#LayerDrawableItem_id */ - public Drawable getDrawable(int index) { - return mLayerState.mChildren[index].mDrawable; + public int getId(int index) { + if (index >= mLayerState.mNum) { + throw new IndexOutOfBoundsException(); + } + return mLayerState.mChildren[index].mId; } /** - * Returns the id of the specified layer. - * - * @param index The index of the layer. + * Returns the number of layers contained within this layer drawable. * - * @return The id of the layer or {@link android.view.View#NO_ID} if the layer has no id. + * @return The number of layers. */ - public int getId(int index) { - return mLayerState.mChildren[index].mId; + public int getNumberOfLayers() { + return mLayerState.mNum; } /** - * Sets (or replaces) the {@link Drawable} for the layer with the given id. + * Replaces the {@link Drawable} for the layer with the given id. * * @param id The layer ID to search for. * @param drawable The replacement {@link Drawable}. @@ -419,31 +467,171 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { * the id was not found). */ public boolean setDrawableByLayerId(int id, Drawable drawable) { + final int index = findIndexByLayerId(id); + if (index < 0) { + return false; + } + + setDrawable(index, drawable); + return true; + } + + /** + * Returns the layer with the specified {@code id}. + * <p> + * If multiple layers have the same ID, returns the layer with the lowest + * index. + * + * @param id The ID of the layer to return. + * @return The index of the layer with the specified ID. + */ + public int findIndexByLayerId(int id) { final ChildDrawable[] layers = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { final ChildDrawable childDrawable = layers[i]; if (childDrawable.mId == id) { - if (childDrawable.mDrawable != null) { - if (drawable != null) { - final Rect bounds = childDrawable.mDrawable.getBounds(); - drawable.setBounds(bounds); - } + return i; + } + } - childDrawable.mDrawable.setCallback(null); - } + return -1; + } - if (drawable != null) { - drawable.setCallback(this); - } + /** + * Sets the drawable for the layer at the specified index. + * + * @param index The index of the layer to modify, must be in the range + * {@code 0...getNumberOfLayers()-1}. + * @param drawable The drawable to set for the layer. + * + * @see #getDrawable(int) + * @attr ref android.R.styleable#LayerDrawableItem_drawable + */ + public void setDrawable(int index, Drawable drawable) { + if (index >= mLayerState.mNum) { + throw new IndexOutOfBoundsException(); + } - childDrawable.mDrawable = drawable; - mLayerState.invalidateCache(); - return true; + final ChildDrawable[] layers = mLayerState.mChildren; + final ChildDrawable childDrawable = layers[index]; + if (childDrawable.mDrawable != null) { + if (drawable != null) { + final Rect bounds = childDrawable.mDrawable.getBounds(); + drawable.setBounds(bounds); } + + childDrawable.mDrawable.setCallback(null); } - return false; + if (drawable != null) { + drawable.setCallback(this); + drawable.setLayoutDirection(getLayoutDirection()); + drawable.setLevel(getLevel()); + } + + childDrawable.mDrawable = drawable; + mLayerState.invalidateCache(); + } + + /** + * Returns the drawable for the layer at the specified index. + * + * @param index The index of the layer, must be in the range + * {@code 0...getNumberOfLayers()-1}. + * @return The {@link Drawable} at the specified layer index. + * + * @see #setDrawable(int, Drawable) + * @attr ref android.R.styleable#LayerDrawableItem_drawable + */ + public Drawable getDrawable(int index) { + if (index >= mLayerState.mNum) { + throw new IndexOutOfBoundsException(); + } + return mLayerState.mChildren[index].mDrawable; + } + + /** + * Sets an explicit size for the specified layer. + * <p> + * <strong>Note:</strong> Setting an explicit layer size changes the + * default layer gravity behavior. See {@link #setLayerGravity(int, int)} + * for more information. + * + * @param index the index of the drawable to adjust + * @param w width in pixels, or -1 to use the intrinsic width + * @param h height in pixels, or -1 to use the intrinsic height + * + * @see #getLayerWidth(int) + * @see #getLayerHeight(int) + * @attr ref android.R.styleable#LayerDrawableItem_width + * @attr ref android.R.styleable#LayerDrawableItem_height + */ + public void setLayerSize(int index, int w, int h) { + final ChildDrawable childDrawable = mLayerState.mChildren[index]; + childDrawable.mWidth = w; + childDrawable.mHeight = h; + } + + /** + * @param index the index of the drawable to adjust + * @return the explicit width of the layer, or -1 if not specified + * + * @see #setLayerSize(int, int, int) + * @attr ref android.R.styleable#LayerDrawableItem_width + */ + public int getLayerWidth(int index) { + final ChildDrawable childDrawable = mLayerState.mChildren[index]; + return childDrawable.mWidth; + } + + /** + * @param index the index of the drawable to adjust + * @return the explicit height of the layer, or -1 if not specified + * + * @see #setLayerSize(int, int, int) + * @attr ref android.R.styleable#LayerDrawableItem_height + */ + public int getLayerHeight(int index) { + final ChildDrawable childDrawable = mLayerState.mChildren[index]; + return childDrawable.mHeight; + } + + /** + * Sets the gravity used to position or stretch the specified layer within + * its container. Gravity is applied after any layer insets (see + * {@link #setLayerInset(int, int, int, int, int)}) or padding (see + * {@link #setPaddingMode(int)}). + * <p> + * If gravity is specified as {@link Gravity#NO_GRAVITY}, the default + * behavior depends on whether an explicit width or height has been set + * (see {@link #setLayerSize(int, int, int)}), If a dimension is not set, + * gravity in that direction defaults to {@link Gravity#FILL_HORIZONTAL} or + * {@link Gravity#FILL_VERTICAL}; otherwise, gravity in that direction + * defaults to {@link Gravity#LEFT} or {@link Gravity#TOP}. + * + * @param index the index of the drawable to adjust + * @param gravity the gravity to set for the layer + * + * @see #getLayerGravity(int) + * @attr ref android.R.styleable#LayerDrawableItem_gravity + */ + public void setLayerGravity(int index, int gravity) { + final ChildDrawable childDrawable = mLayerState.mChildren[index]; + childDrawable.mGravity = gravity; + } + + /** + * @param index the index of the layer + * @return the gravity used to position or stretch the specified layer + * within its container + * + * @see #setLayerGravity(int, int) + * @attr ref android.R.styleable#LayerDrawableItem_gravity + */ + public int getLayerGravity(int index) { + final ChildDrawable childDrawable = mLayerState.mChildren[index]; + return childDrawable.mGravity; } /** @@ -454,13 +642,43 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { * @param t number of pixels to add to the top bound * @param r number of pixels to subtract from the right bound * @param b number of pixels to subtract from the bottom bound + * + * @attr ref android.R.styleable#LayerDrawableItem_left + * @attr ref android.R.styleable#LayerDrawableItem_top + * @attr ref android.R.styleable#LayerDrawableItem_right + * @attr ref android.R.styleable#LayerDrawableItem_bottom */ public void setLayerInset(int index, int l, int t, int r, int b) { + setLayerInsetInternal(index, l, t, r, b, UNDEFINED_INSET, UNDEFINED_INSET); + } + + /** + * Specifies the relative insets in pixels for the drawable at the + * specified index. + * + * @param index the index of the drawable to adjust + * @param s number of pixels to inset from the start bound + * @param t number of pixels to inset from the top bound + * @param e number of pixels to inset from the end bound + * @param b number of pixels to inset from the bottom bound + * + * @attr ref android.R.styleable#LayerDrawableItem_start + * @attr ref android.R.styleable#LayerDrawableItem_top + * @attr ref android.R.styleable#LayerDrawableItem_end + * @attr ref android.R.styleable#LayerDrawableItem_bottom + */ + public void setLayerInsetRelative(int index, int s, int t, int e, int b) { + setLayerInsetInternal(index, 0, t, 0, b, s, e); + } + + private void setLayerInsetInternal(int index, int l, int t, int r, int b, int s, int e) { final ChildDrawable childDrawable = mLayerState.mChildren[index]; childDrawable.mInsetL = l; childDrawable.mInsetT = t; childDrawable.mInsetR = r; childDrawable.mInsetB = b; + childDrawable.mInsetS = s; + childDrawable.mInsetE = e; } /** @@ -648,6 +866,18 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } @Override + public boolean getDither() { + final ChildDrawable[] array = mLayerState.mChildren; + if (mLayerState.mNum > 0) { + // All layers should have the same dither set on them - just return + // the first one + return array[0].mDrawable.getDither(); + } else { + return super.getDither(); + } + } + + @Override public void setAlpha(int alpha) { final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; @@ -758,7 +988,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } if (paddingChanged) { - onBoundsChange(getBounds()); + updateLayerBounds(getBounds()); } return changed; @@ -783,7 +1013,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } if (paddingChanged) { - onBoundsChange(getBounds()); + updateLayerBounds(getBounds()); } return changed; @@ -791,18 +1021,51 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { @Override protected void onBoundsChange(Rect bounds) { + updateLayerBounds(bounds); + } + + private void updateLayerBounds(Rect bounds) { int padL = 0; int padT = 0; int padR = 0; int padB = 0; + final Rect outRect = mTmpOutRect; + final int layoutDirection = getLayoutDirection(); final boolean nest = mLayerState.mPaddingMode == PADDING_MODE_NEST; final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { final ChildDrawable r = array[i]; - r.mDrawable.setBounds(bounds.left + r.mInsetL + padL, bounds.top + r.mInsetT + padT, - bounds.right - r.mInsetR - padR, bounds.bottom - r.mInsetB - padB); + final Drawable d = r.mDrawable; + final Rect container = mTmpContainer; + container.set(d.getBounds()); + + // Take the resolved layout direction into account. If start / end + // padding are defined, they will be resolved (hence overriding) to + // left / right or right / left depending on the resolved layout + // direction. If start / end padding are not defined, use the + // left / right ones. + final int insetL, insetR; + if (layoutDirection == LayoutDirection.RTL) { + insetL = r.mInsetE == UNDEFINED_INSET ? r.mInsetL : r.mInsetE; + insetR = r.mInsetS == UNDEFINED_INSET ? r.mInsetR : r.mInsetS; + } else { + insetL = r.mInsetS == UNDEFINED_INSET ? r.mInsetL : r.mInsetS; + insetR = r.mInsetE == UNDEFINED_INSET ? r.mInsetR : r.mInsetE; + } + + // Establish containing region based on aggregate padding and + // requested insets for the current layer. + container.set(bounds.left + insetL + padL, bounds.top + r.mInsetT + padT, + bounds.right - insetR - padR, bounds.bottom - r.mInsetB - padB); + + // Apply resolved gravity to drawable based on resolved size. + final int gravity = resolveGravity(r.mGravity, r.mWidth, r.mHeight); + final int w = r.mWidth < 0 ? d.getIntrinsicWidth() : r.mWidth; + final int h = r.mHeight < 0 ? d.getIntrinsicHeight() : r.mHeight; + Gravity.apply(gravity, w, h, container, outRect, layoutDirection); + d.setBounds(outRect); if (nest) { padL += mPaddingL[i]; @@ -813,6 +1076,38 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } } + /** + * Resolves layer gravity given explicit gravity and dimensions. + * <p> + * If the client hasn't specified a gravity but has specified an explicit + * dimension, defaults to START or TOP. Otherwise, defaults to FILL to + * preserve legacy behavior. + * + * @param gravity + * @param width + * @param height + * @return + */ + private int resolveGravity(int gravity, int width, int height) { + if (!Gravity.isHorizontal(gravity)) { + if (width < 0) { + gravity |= Gravity.FILL_HORIZONTAL; + } else { + gravity |= Gravity.START; + } + } + + if (!Gravity.isVertical(gravity)) { + if (height < 0) { + gravity |= Gravity.FILL_VERTICAL; + } else { + gravity |= Gravity.TOP; + } + } + + return gravity; + } + @Override public int getIntrinsicWidth() { int width = -1; @@ -824,7 +1119,8 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { final ChildDrawable r = array[i]; - final int w = r.mDrawable.getIntrinsicWidth() + r.mInsetL + r.mInsetR + padL + padR; + final int minWidth = r.mWidth < 0 ? r.mDrawable.getIntrinsicWidth() : r.mWidth; + final int w = minWidth + r.mInsetL + r.mInsetR + padL + padR; if (w > width) { width = w; } @@ -849,7 +1145,8 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { final ChildDrawable r = array[i]; - int h = r.mDrawable.getIntrinsicHeight() + r.mInsetT + r.mInsetB + padT + padB; + final int minHeight = r.mHeight < 0 ? r.mDrawable.getIntrinsicHeight() : r.mHeight; + final int h = minHeight + r.mInsetT + r.mInsetB + padT + padB; if (h > height) { height = h; } @@ -936,18 +1233,24 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { /** @hide */ @Override public void setLayoutDirection(int layoutDirection) { + super.setLayoutDirection(layoutDirection); final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { array[i].mDrawable.setLayoutDirection(layoutDirection); } - super.setLayoutDirection(layoutDirection); + updateLayerBounds(getBounds()); } static class ChildDrawable { public Drawable mDrawable; public int[] mThemeAttrs; public int mInsetL, mInsetT, mInsetR, mInsetB; + public int mInsetS = UNDEFINED_INSET; + public int mInsetE = UNDEFINED_INSET; + public int mWidth = -1; + public int mHeight = -1; + public int mGravity = Gravity.NO_GRAVITY; public int mId = View.NO_ID; ChildDrawable() { @@ -969,6 +1272,11 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { mInsetT = orig.mInsetT; mInsetR = orig.mInsetR; mInsetB = orig.mInsetB; + mInsetS = orig.mInsetS; + mInsetE = orig.mInsetE; + mWidth = orig.mWidth; + mHeight = orig.mHeight; + mGravity = orig.mGravity; mId = orig.mId; } } diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java index b87ae92..617bf7c 100644 --- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java +++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java @@ -374,6 +374,11 @@ public class NinePatchDrawable extends Drawable { } @Override + public boolean getDither() { + return mPaint == null ? DEFAULT_DITHER : mPaint.isDither(); + } + + @Override public void setAutoMirrored(boolean mirrored) { mNinePatchState.mAutoMirrored = mirrored; } @@ -401,6 +406,8 @@ public class NinePatchDrawable extends Drawable { final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.NinePatchDrawable); updateStateFromTypedArray(a); a.recycle(); + + updateLocalState(r); } /** @@ -467,12 +474,6 @@ public class NinePatchDrawable extends Drawable { if (tint != null) { state.mTint = tint; } - - // Update local properties. - initializeWithState(state, r); - - // Push density applied by setNinePatchState into state. - state.mTargetDensity = mTargetDensity; } @Override @@ -480,23 +481,32 @@ public class NinePatchDrawable extends Drawable { super.applyTheme(t); final NinePatchState state = mNinePatchState; - if (state == null || state.mThemeAttrs == null) { + if (state == null) { return; } - final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.NinePatchDrawable); - try { - updateStateFromTypedArray(a); - } catch (XmlPullParserException e) { - throw new RuntimeException(e); - } finally { - a.recycle(); + if (state.mThemeAttrs != null) { + final TypedArray a = t.resolveAttributes( + state.mThemeAttrs, R.styleable.NinePatchDrawable); + try { + updateStateFromTypedArray(a); + } catch (XmlPullParserException e) { + throw new RuntimeException(e); + } finally { + a.recycle(); + } + } + + if (state.mTint != null && state.mTint.canApplyTheme()) { + state.mTint.applyTheme(t); } + + updateLocalState(t.getResources()); } @Override public boolean canApplyTheme() { - return mNinePatchState != null && mNinePatchState.mThemeAttrs != null; + return mNinePatchState != null && mNinePatchState.canApplyTheme(); } public Paint getPaint() { @@ -645,7 +655,8 @@ public class NinePatchDrawable extends Drawable { @Override public boolean canApplyTheme() { - return mThemeAttrs != null; + return mThemeAttrs != null + || (mTint != null && mTint.canApplyTheme()); } @Override @@ -680,19 +691,25 @@ public class NinePatchDrawable extends Drawable { private NinePatchDrawable(NinePatchState state, Resources res) { mNinePatchState = state; - initializeWithState(mNinePatchState, res); + updateLocalState(res); + + // Push density applied by setNinePatchState into state. + mNinePatchState.mTargetDensity = mTargetDensity; } /** * Initializes local dynamic properties from state. */ - private void initializeWithState(NinePatchState state, Resources res) { + private void updateLocalState(Resources res) { + final NinePatchState state = mNinePatchState; + if (res != null) { mTargetDensity = res.getDisplayMetrics().densityDpi; } else { mTargetDensity = state.mTargetDensity; } + // If we can, avoid calling any methods that initialize Paint. if (state.mDither != DEFAULT_DITHER) { setDither(state.mDither); diff --git a/graphics/java/android/graphics/drawable/PictureDrawable.java b/graphics/java/android/graphics/drawable/PictureDrawable.java index 6dcda1f..583cffb 100644 --- a/graphics/java/android/graphics/drawable/PictureDrawable.java +++ b/graphics/java/android/graphics/drawable/PictureDrawable.java @@ -88,12 +88,6 @@ public class PictureDrawable extends Drawable { } @Override - public void setFilterBitmap(boolean filter) {} - - @Override - public void setDither(boolean dither) {} - - @Override public void setColorFilter(ColorFilter colorFilter) {} @Override diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java index bb1d3cb..138d73a 100644 --- a/graphics/java/android/graphics/drawable/Ripple.java +++ b/graphics/java/android/graphics/drawable/Ripple.java @@ -46,8 +46,7 @@ class Ripple { private static final long RIPPLE_ENTER_DELAY = 80; // Hardware animators. - private final ArrayList<RenderNodeAnimator> mRunningAnimations = - new ArrayList<RenderNodeAnimator>(); + private final ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<>(); private final RippleDrawable mOwner; @@ -117,8 +116,8 @@ class Ripple { mStartingY = startingY; } - public void setup(int maxRadius, float density) { - if (maxRadius != RippleDrawable.RADIUS_AUTO) { + public void setup(float maxRadius, float density) { + if (maxRadius >= 0) { mHasMaxRadius = true; mOuterRadius = maxRadius; } else { diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java index fae4902..ef35289 100644 --- a/graphics/java/android/graphics/drawable/RippleBackground.java +++ b/graphics/java/android/graphics/drawable/RippleBackground.java @@ -49,8 +49,7 @@ class RippleBackground { private static final int ENTER_DURATION_FAST = 100; // Hardware animators. - private final ArrayList<RenderNodeAnimator> mRunningAnimations = - new ArrayList<RenderNodeAnimator>(); + private final ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<>(); private final RippleDrawable mOwner; @@ -105,8 +104,8 @@ class RippleBackground { mBounds = bounds; } - public void setup(int maxRadius, float density) { - if (maxRadius != RippleDrawable.RADIUS_AUTO) { + public void setup(float maxRadius, float density) { + if (maxRadius >= 0) { mHasMaxRadius = true; mOuterRadius = maxRadius; } else { diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java index 1263447..556c59f 100644 --- a/graphics/java/android/graphics/drawable/RippleDrawable.java +++ b/graphics/java/android/graphics/drawable/RippleDrawable.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -92,19 +92,17 @@ import java.util.Arrays; * @attr ref android.R.styleable#RippleDrawable_color */ public class RippleDrawable extends LayerDrawable { + /** + * Radius value that specifies the ripple radius should be computed based + * on the size of the ripple's container. + */ + public static final int RADIUS_AUTO = -1; + private static final int MASK_UNKNOWN = -1; private static final int MASK_NONE = 0; private static final int MASK_CONTENT = 1; private static final int MASK_EXPLICIT = 2; - /** - * Constant for automatically determining the maximum ripple radius. - * - * @see #setMaxRadius(int) - * @hide - */ - public static final int RADIUS_AUTO = -1; - /** The maximum number of ripples supported. */ private static final int MAX_RIPPLES = 10; @@ -198,7 +196,7 @@ public class RippleDrawable extends LayerDrawable { setColor(color); ensurePadding(); - initializeFromState(); + updateLocalState(); } @Override @@ -352,11 +350,40 @@ public class RippleDrawable extends LayerDrawable { return true; } + /** + * Sets the ripple color. + * + * @param color Ripple color as a color state list. + * + * @attr ref android.R.styleable#RippleDrawable_color + */ public void setColor(ColorStateList color) { mState.mColor = color; invalidateSelf(); } + /** + * Sets the radius in pixels of the fully expanded ripple. + * + * @param radius ripple radius in pixels, or {@link #RADIUS_AUTO} to + * compute the radius based on the container size + * @attr ref android.R.styleable#RippleDrawable_radius + */ + public void setRadius(int radius) { + mState.mMaxRadius = radius; + invalidateSelf(); + } + + /** + * @return the radius in pixels of the fully expanded ripple if an explicit + * radius has been set, or {@link #RADIUS_AUTO} if the radius is + * computed based on the container size + * @attr ref android.R.styleable#RippleDrawable_radius + */ + public int getRadius() { + return mState.mMaxRadius; + } + @Override public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) throws XmlPullParserException, IOException { @@ -370,7 +397,8 @@ public class RippleDrawable extends LayerDrawable { super.inflate(r, parser, attrs, theme); setTargetDensity(r.getDisplayMetrics()); - initializeFromState(); + + updateLocalState(); } @Override @@ -422,6 +450,9 @@ public class RippleDrawable extends LayerDrawable { mState.mColor = color; } + mState.mMaxRadius = a.getDimensionPixelSize( + R.styleable.RippleDrawable_radius, mState.mMaxRadius); + verifyRequiredAttributes(a); } @@ -450,21 +481,27 @@ public class RippleDrawable extends LayerDrawable { super.applyTheme(t); final RippleState state = mState; - if (state == null || state.mTouchThemeAttrs == null) { + if (state == null) { return; } - final TypedArray a = t.resolveAttributes(state.mTouchThemeAttrs, - R.styleable.RippleDrawable); - try { - updateStateFromTypedArray(a); - } catch (XmlPullParserException e) { - throw new RuntimeException(e); - } finally { - a.recycle(); + if (state.mTouchThemeAttrs != null) { + final TypedArray a = t.resolveAttributes(state.mTouchThemeAttrs, + R.styleable.RippleDrawable); + try { + updateStateFromTypedArray(a); + } catch (XmlPullParserException e) { + throw new RuntimeException(e); + } finally { + a.recycle(); + } } - initializeFromState(); + if (state.mColor != null && state.mColor.canApplyTheme()) { + state.mColor.applyTheme(t); + } + + updateLocalState(); } @Override @@ -931,7 +968,9 @@ public class RippleDrawable extends LayerDrawable { @Override public boolean canApplyTheme() { - return mTouchThemeAttrs != null || super.canApplyTheme(); + return mTouchThemeAttrs != null + || (mColor != null && mColor.canApplyTheme()) + || super.canApplyTheme(); } @Override @@ -945,36 +984,6 @@ public class RippleDrawable extends LayerDrawable { } } - /** - * Sets the maximum ripple radius in pixels. The default value of - * {@link #RADIUS_AUTO} defines the radius as the distance from the center - * of the drawable bounds (or hotspot bounds, if specified) to a corner. - * - * @param maxRadius the maximum ripple radius in pixels or - * {@link #RADIUS_AUTO} to automatically determine the maximum - * radius based on the bounds - * @see #getMaxRadius() - * @see #setHotspotBounds(int, int, int, int) - * @hide - */ - public void setMaxRadius(int maxRadius) { - if (maxRadius != RADIUS_AUTO && maxRadius < 0) { - throw new IllegalArgumentException("maxRadius must be RADIUS_AUTO or >= 0"); - } - - mState.mMaxRadius = maxRadius; - } - - /** - * @return the maximum ripple radius in pixels, or {@link #RADIUS_AUTO} if - * the radius is determined automatically - * @see #setMaxRadius(int) - * @hide - */ - public int getMaxRadius() { - return mState.mMaxRadius; - } - private RippleDrawable(RippleState state, Resources res) { mState = new RippleState(state, this, res); mLayerState = mState; @@ -987,10 +996,10 @@ public class RippleDrawable extends LayerDrawable { mDensity = res.getDisplayMetrics().density; } - initializeFromState(); + updateLocalState(); } - private void initializeFromState() { + private void updateLocalState() { // Initialize from constant state. mMask = findDrawableByLayerId(R.id.mask); } diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java index a3d8c92..c208c03 100644 --- a/graphics/java/android/graphics/drawable/ShapeDrawable.java +++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java @@ -329,6 +329,11 @@ public class ShapeDrawable extends Drawable { } @Override + public boolean getDither() { + return mShapeState.mPaint.isDither(); + } + + @Override protected void onBoundsChange(Rect bounds) { super.onBoundsChange(bounds); updateShape(); @@ -402,7 +407,7 @@ public class ShapeDrawable extends Drawable { } // Update local properties. - initializeWithState(mShapeState, r); + updateLocalState(r); } @Override @@ -410,16 +415,23 @@ public class ShapeDrawable extends Drawable { super.applyTheme(t); final ShapeState state = mShapeState; - if (state == null || state.mThemeAttrs == null) { + if (state == null) { return; } - final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ShapeDrawable); - updateStateFromTypedArray(a); - a.recycle(); + if (state.mThemeAttrs != null) { + final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ShapeDrawable); + updateStateFromTypedArray(a); + a.recycle(); + } + + // Apply theme to contained color state list. + if (state.mTint != null && state.mTint.canApplyTheme()) { + state.mTint.applyTheme(t); + } // Update local properties. - initializeWithState(state, t.getResources()); + updateLocalState(t.getResources()); } private void updateStateFromTypedArray(TypedArray a) { @@ -550,7 +562,8 @@ public class ShapeDrawable extends Drawable { @Override public boolean canApplyTheme() { - return mThemeAttrs != null; + return mThemeAttrs != null + || (mTint != null && mTint.canApplyTheme()); } @Override @@ -576,7 +589,7 @@ public class ShapeDrawable extends Drawable { private ShapeDrawable(ShapeState state, Resources res) { mShapeState = state; - initializeWithState(state, res); + updateLocalState(res); } /** @@ -584,8 +597,8 @@ public class ShapeDrawable extends Drawable { * after significant state changes, e.g. from the One True Constructor and * after inflating or applying a theme. */ - private void initializeWithState(ShapeState state, Resources res) { - mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); + private void updateLocalState(Resources res) { + mTintFilter = updateTintFilter(mTintFilter, mShapeState.mTint, mShapeState.mTintMode); } /** diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index 8b0f635..5f1dcec 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -150,7 +150,8 @@ import java.util.Stack; * * <dl> * <dt><code><clip-path></code></dt> - * <dd>Defines path to be the current clip. + * <dd>Defines path to be the current clip. Note that the clip path only apply to + * the current group and its children. * <dl> * <dt><code>android:name</code></dt> * <dd>Defines the name of the clip path.</dd> @@ -369,8 +370,13 @@ public class VectorDrawable extends Drawable { super.applyTheme(t); final VectorDrawableState state = mVectorState; - if (state != null && state.mThemeAttrs != null) { - final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.VectorDrawable); + if (state == null) { + return; + } + + if (state.mThemeAttrs != null) { + final TypedArray a = t.resolveAttributes( + state.mThemeAttrs, R.styleable.VectorDrawable); try { state.mCacheDirty = true; updateStateFromTypedArray(a); @@ -379,14 +385,20 @@ public class VectorDrawable extends Drawable { } finally { a.recycle(); } + } - mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); + // Apply theme to contained color state list. + if (state.mTint != null && state.mTint.canApplyTheme()) { + state.mTint.applyTheme(t); } final VPathRenderer path = state.mVPathRenderer; if (path != null && path.canApplyTheme()) { path.applyTheme(t); } + + // Update local state. + mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); } /** @@ -750,7 +762,9 @@ public class VectorDrawable extends Drawable { @Override public boolean canApplyTheme() { - return mThemeAttrs != null || (mVPathRenderer != null && mVPathRenderer.canApplyTheme()) + return mThemeAttrs != null + || (mVPathRenderer != null && mVPathRenderer.canApplyTheme()) + || (mTint != null && mTint.canApplyTheme()) || super.canApplyTheme(); } @@ -913,9 +927,10 @@ public class VectorDrawable extends Drawable { // Basically the Mfinal = Mviewport * M0 * M1 * M2; // Mi the local matrix at level i of the group tree. currentGroup.mStackedMatrix.set(currentMatrix); - currentGroup.mStackedMatrix.preConcat(currentGroup.mLocalMatrix); + // Save the current clip information, which is local to this group. + canvas.save(); // Draw the group tree in the same order as the XML file. for (int i = 0; i < currentGroup.mChildren.size(); i++) { Object child = currentGroup.mChildren.get(i); @@ -928,6 +943,7 @@ public class VectorDrawable extends Drawable { drawPath(currentGroup, childPath, canvas, w, h, filter); } } + canvas.restore(); } public void draw(Canvas canvas, int w, int h, ColorFilter filter) { |