diff --git a/src/api-impl-jni/generated_headers/android_graphics_Canvas.h b/src/api-impl-jni/generated_headers/android_graphics_Canvas.h index 98c4890d..62d2908c 100644 --- a/src/api-impl-jni/generated_headers/android_graphics_Canvas.h +++ b/src/api-impl-jni/generated_headers/android_graphics_Canvas.h @@ -7,6 +7,8 @@ #ifdef __cplusplus extern "C" { #endif +#undef android_graphics_Canvas_HAS_ALPHA_LAYER_SAVE_FLAG +#define android_graphics_Canvas_HAS_ALPHA_LAYER_SAVE_FLAG 4L /* * Class: android_graphics_Canvas * Method: native_canvas_from_bitmap diff --git a/src/api-impl-jni/generated_headers/android_graphics_GskCanvas.h b/src/api-impl-jni/generated_headers/android_graphics_GskCanvas.h index ea5518bd..f54286a1 100644 --- a/src/api-impl-jni/generated_headers/android_graphics_GskCanvas.h +++ b/src/api-impl-jni/generated_headers/android_graphics_GskCanvas.h @@ -7,6 +7,8 @@ #ifdef __cplusplus extern "C" { #endif +#undef android_graphics_GskCanvas_HAS_ALPHA_LAYER_SAVE_FLAG +#define android_graphics_GskCanvas_HAS_ALPHA_LAYER_SAVE_FLAG 4L /* * Class: android_graphics_GskCanvas * Method: native_drawBitmap diff --git a/src/api-impl/android/app/usage/UsageStatsManager.java b/src/api-impl/android/app/usage/UsageStatsManager.java new file mode 100644 index 00000000..511d279b --- /dev/null +++ b/src/api-impl/android/app/usage/UsageStatsManager.java @@ -0,0 +1,5 @@ +package android.app.usage; + +public class UsageStatsManager { + +} diff --git a/src/api-impl/android/graphics/Canvas.java b/src/api-impl/android/graphics/Canvas.java index dd450f3c..908f1303 100644 --- a/src/api-impl/android/graphics/Canvas.java +++ b/src/api-impl/android/graphics/Canvas.java @@ -1,6 +1,8 @@ package android.graphics; public class Canvas { + public static final int HAS_ALPHA_LAYER_SAVE_FLAG = (1 << 2); + public long skia_canvas; public long widget; diff --git a/src/api-impl/android/graphics/PixelFormat.java b/src/api-impl/android/graphics/PixelFormat.java new file mode 100644 index 00000000..76057986 --- /dev/null +++ b/src/api-impl/android/graphics/PixelFormat.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.graphics; + +public class PixelFormat { + /* these constants need to match those in hardware/hardware.h */ + + public static final int UNKNOWN = 0; + + /** + * System chooses a format that supports translucency (many alpha bits) + */ + public static final int TRANSLUCENT = -3; + + /** + * System chooses a format that supports transparency + * (at least 1 alpha bit) + */ + public static final int TRANSPARENT = -2; + + /** + * System chooses an opaque format (no alpha bits required) + */ + public static final int OPAQUE = -1; + + public static final int RGBA_8888 = 1; + public static final int RGBX_8888 = 2; + public static final int RGB_888 = 3; + public static final int RGB_565 = 4; + + @Deprecated + public static final int RGBA_5551 = 6; + @Deprecated + public static final int RGBA_4444 = 7; + @Deprecated + public static final int A_8 = 8; + @Deprecated + public static final int L_8 = 9; + @Deprecated + public static final int LA_88 = 0xA; + @Deprecated + public static final int RGB_332 = 0xB; + + /** + * @deprecated use {@link android.graphics.ImageFormat#NV16 + * ImageFormat.NV16} instead. + */ + @Deprecated + public static final int YCbCr_422_SP = 0x10; + + /** + * @deprecated use {@link android.graphics.ImageFormat#NV21 + * ImageFormat.NV21} instead. + */ + @Deprecated + public static final int YCbCr_420_SP = 0x11; + + /** + * @deprecated use {@link android.graphics.ImageFormat#YUY2 + * ImageFormat.YUY2} instead. + */ + @Deprecated + public static final int YCbCr_422_I = 0x14; + + /** + * @deprecated use {@link android.graphics.ImageFormat#JPEG + * ImageFormat.JPEG} instead. + */ + @Deprecated + public static final int JPEG = 0x100; + + public static void getPixelFormatInfo(int format, PixelFormat info) { + switch (format) { + case RGBA_8888: + case RGBX_8888: + info.bitsPerPixel = 32; + info.bytesPerPixel = 4; + break; + case RGB_888: + info.bitsPerPixel = 24; + info.bytesPerPixel = 3; + break; + case RGB_565: + case RGBA_5551: + case RGBA_4444: + case LA_88: + info.bitsPerPixel = 16; + info.bytesPerPixel = 2; + break; + case A_8: + case L_8: + case RGB_332: + info.bitsPerPixel = 8; + info.bytesPerPixel = 1; + break; + case YCbCr_422_SP: + case YCbCr_422_I: + info.bitsPerPixel = 16; + info.bytesPerPixel = 1; + break; + case YCbCr_420_SP: + info.bitsPerPixel = 12; + info.bytesPerPixel = 1; + break; + default: + throw new IllegalArgumentException("unkonwon pixel format " + format); + } + } + + public static boolean formatHasAlpha(int format) { + switch (format) { + case PixelFormat.A_8: + case PixelFormat.LA_88: + case PixelFormat.RGBA_4444: + case PixelFormat.RGBA_5551: + case PixelFormat.RGBA_8888: + case PixelFormat.TRANSLUCENT: + case PixelFormat.TRANSPARENT: + return true; + } + return false; + } + + public int bytesPerPixel; + public int bitsPerPixel; +} diff --git a/src/api-impl/android/graphics/drawable/Drawable.java b/src/api-impl/android/graphics/drawable/Drawable.java index ceb28255..c7f69ae7 100644 --- a/src/api-impl/android/graphics/drawable/Drawable.java +++ b/src/api-impl/android/graphics/drawable/Drawable.java @@ -15,8 +15,10 @@ import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.content.res.Resources.Theme; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.util.AttributeSet; import android.util.TypedValue; @@ -28,6 +30,8 @@ public class Drawable { public void unscheduleDrawable(Drawable drawable, Runnable runnable); } + static final PorterDuff.Mode DEFAULT_TINT_MODE = PorterDuff.Mode.SRC_IN; + private Rect mBounds = new Rect(); private int[] mStateSet = new int[0]; public long paintable; @@ -140,9 +144,24 @@ public class Drawable { public int getIntrinsicWidth() {return 0;} public int getIntrinsicHeight() {return 0;} - public void setTintList (ColorStateList tint) {} + public void setTintList(ColorStateList tint) {} - public void setTint(int tint) {} + public void setTint(int tint) { + System.out.println("setTint("+tint+")"); + setTintList(ColorStateList.valueOf(tint)); + } + + PorterDuffColorFilter updateTintFilter(PorterDuffColorFilter tintFilter, ColorStateList tint, PorterDuff.Mode tintMode) { + System.out.println("updateTintFilter("+tintFilter+", "+tint+", "+tintMode+")"); + if (tint == null || tintMode == null) { + return null; + } + final int color = tint.getColorForState(getState(), Color.TRANSPARENT); + if (tintFilter == null || tintFilter.getColor() != color || tintFilter.getMode() != tintMode) { + return new PorterDuffColorFilter(color, tintMode); + } + return tintFilter; + } public boolean isStateful() { return false; diff --git a/src/api-impl/android/graphics/drawable/GradientDrawable.java b/src/api-impl/android/graphics/drawable/GradientDrawable.java index c2e98911..d9f41752 100644 --- a/src/api-impl/android/graphics/drawable/GradientDrawable.java +++ b/src/api-impl/android/graphics/drawable/GradientDrawable.java @@ -1,10 +1,1350 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package android.graphics.drawable; +import android.content.res.ColorStateList; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.DashPathEffect; +import android.graphics.LinearGradient; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.RadialGradient; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Shader; +//import android.graphics.SweepGradient; +import android.util.AttributeSet; +import android.util.Log; +import android.util.TypedValue; + +import com.android.internal.R; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; + +/** + * A Drawable with a color gradient for buttons, backgrounds, etc. + * + *

It can be defined in an XML file with the <shape> element. For more + * information, see the guide to Drawable Resources.

+ * + * @attr ref android.R.styleable#GradientDrawable_visible + * @attr ref android.R.styleable#GradientDrawable_shape + * @attr ref android.R.styleable#GradientDrawable_innerRadiusRatio + * @attr ref android.R.styleable#GradientDrawable_innerRadius + * @attr ref android.R.styleable#GradientDrawable_thicknessRatio + * @attr ref android.R.styleable#GradientDrawable_thickness + * @attr ref android.R.styleable#GradientDrawable_useLevel + * @attr ref android.R.styleable#GradientDrawableSize_width + * @attr ref android.R.styleable#GradientDrawableSize_height + * @attr ref android.R.styleable#GradientDrawableGradient_startColor + * @attr ref android.R.styleable#GradientDrawableGradient_centerColor + * @attr ref android.R.styleable#GradientDrawableGradient_endColor + * @attr ref android.R.styleable#GradientDrawableGradient_useLevel + * @attr ref android.R.styleable#GradientDrawableGradient_angle + * @attr ref android.R.styleable#GradientDrawableGradient_type + * @attr ref android.R.styleable#GradientDrawableGradient_centerX + * @attr ref android.R.styleable#GradientDrawableGradient_centerY + * @attr ref android.R.styleable#GradientDrawableGradient_gradientRadius + * @attr ref android.R.styleable#GradientDrawableSolid_color + * @attr ref android.R.styleable#GradientDrawableStroke_width + * @attr ref android.R.styleable#GradientDrawableStroke_color + * @attr ref android.R.styleable#GradientDrawableStroke_dashWidth + * @attr ref android.R.styleable#GradientDrawableStroke_dashGap + * @attr ref android.R.styleable#GradientDrawablePadding_left + * @attr ref android.R.styleable#GradientDrawablePadding_top + * @attr ref android.R.styleable#GradientDrawablePadding_right + * @attr ref android.R.styleable#GradientDrawablePadding_bottom + */ public class GradientDrawable extends Drawable { + /** + * Shape is a rectangle, possibly with rounded corners + */ + public static final int RECTANGLE = 0; - public void setColor(int color) {} + /** + * Shape is an ellipse + */ + public static final int OVAL = 1; - public void setCornerRadius(float cornerRadius) {} + /** + * Shape is a line + */ + public static final int LINE = 2; - public void setShape(int shape) {} + /** + * Shape is a ring. + */ + public static final int RING = 3; + + /** + * Gradient is linear (default.) + */ + public static final int LINEAR_GRADIENT = 0; + + /** + * Gradient is circular. + */ + public static final int RADIAL_GRADIENT = 1; + + /** + * Gradient is a sweep. + */ + public static final int SWEEP_GRADIENT = 2; + + 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 ColorFilter mColorFilter; // optional, set by the caller + private PorterDuffColorFilter mTintFilter; + private int mAlpha = 0xFF; // modified by the caller + private boolean mDither; + + 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 boolean mMutated; + private Path mRingPath; + private boolean mPathIsDirty = true; + + /** + * Controls how the gradient is oriented relative to the drawable's bounds + */ + public enum Orientation { + /** + draw the gradient from the top to the bottom + */ + TOP_BOTTOM, + /** + draw the gradient from the top-right to the bottom-left + */ + TR_BL, + /** + draw the gradient from the right to the left + */ + RIGHT_LEFT, + /** + draw the gradient from the bottom-right to the top-left + */ + BR_TL, + /** + draw the gradient from the bottom to the top + */ + BOTTOM_TOP, + /** + draw the gradient from the bottom-left to the top-right + */ + BL_TR, + /** + draw the gradient from the left to the right + */ + LEFT_RIGHT, + /** + draw the gradient from the top-left to the bottom-right + */ + TL_BR, + } + + public GradientDrawable() { + this(new GradientState(Orientation.TOP_BOTTOM, null)); + } + + /** + * Create a new gradient drawable given an orientation and an array + * of colors for the gradient. + */ + public GradientDrawable(Orientation orientation, int[] colors) { + this(new GradientState(orientation, colors)); + } + + @Override + public boolean getPadding(Rect padding) { + if (mPadding != null) { + padding.set(mPadding); + return true; + } else { + return super.getPadding(padding); + } + } + + /** + *

Specify radii for each of the 4 corners. For each corner, the array + * contains 2 values, [X_radius, Y_radius]. The corners are ordered + * top-left, top-right, bottom-right, bottom-left. This property + * is honored only when the shape is of type {@link #RECTANGLE}.

+ *

Note: changing this property will affect all instances + * of a drawable loaded from a resource. It is recommended to invoke + * {@link #mutate()} before changing this property.

+ * + * @param radii 4 pairs of X and Y radius for each corner, specified in pixels. + * The length of this array must be >= 8 + * + * @see #mutate() + * @see #setCornerRadii(float[]) + * @see #setShape(int) + */ + public void setCornerRadii(float[] radii) { + mGradientState.setCornerRadii(radii); + mPathIsDirty = true; + invalidateSelf(); + } + + /** + *

Specify radius for the corners of the gradient. If this is > 0, then the + * drawable is drawn in a round-rectangle, rather than a rectangle. This property + * is honored only when the shape is of type {@link #RECTANGLE}.

+ *

Note: changing this property will affect all instances + * of a drawable loaded from a resource. It is recommended to invoke + * {@link #mutate()} before changing this property.

+ * + * @param radius The radius in pixels of the corners of the rectangle shape + * + * @see #mutate() + * @see #setCornerRadii(float[]) + * @see #setShape(int) + */ + public void setCornerRadius(float radius) { + mGradientState.setCornerRadius(radius); + mPathIsDirty = true; + invalidateSelf(); + } + + /** + *

Set the stroke width and color for the drawable. If width is zero, + * then no stroke is drawn.

+ *

Note: changing this property will affect all instances + * of a drawable loaded from a resource. It is recommended to invoke + * {@link #mutate()} before changing this property.

+ * + * @param width The width in pixels of the stroke + * @param color The color of the stroke + * + * @see #mutate() + * @see #setStroke(int, int, float, float) + */ + public void setStroke(int width, int color) { + setStroke(width, color, 0, 0); + } + + /** + *

Set the stroke width and color for the drawable. If width is zero, + * then no stroke is drawn. This method can also be used to dash the stroke.

+ *

Note: changing this property will affect all instances + * of a drawable loaded from a resource. It is recommended to invoke + * {@link #mutate()} before changing this property.

+ * + * @param width The width in pixels of the stroke + * @param color The color of the stroke + * @param dashWidth The length in pixels of the dashes, set to 0 to disable dashes + * @param dashGap The gap in pixels between dashes + * + * @see #mutate() + * @see #setStroke(int, int) + */ + public void setStroke(int width, int color, float dashWidth, float dashGap) { + mGradientState.setStroke(width, color, dashWidth, dashGap); + + if (mStrokePaint == null) { + mStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mStrokePaint.setStyle(Paint.Style.STROKE); + } + mStrokePaint.setStrokeWidth(width); + mStrokePaint.setColor(color); + + DashPathEffect e = null; + if (dashWidth > 0) { + e = new DashPathEffect(new float[] {dashWidth, dashGap}, 0); + } + mStrokePaint.setPathEffect(e); + invalidateSelf(); + } + + /** + *

Sets the size of the shape drawn by this drawable.

+ *

Note: changing this property will affect all instances + * of a drawable loaded from a resource. It is recommended to invoke + * {@link #mutate()} before changing this property.

+ * + * @param width The width of the shape used by this drawable + * @param height The height of the shape used by this drawable + * + * @see #mutate() + * @see #setGradientType(int) + */ + public void setSize(int width, int height) { + mGradientState.setSize(width, height); + mPathIsDirty = true; + invalidateSelf(); + } + + /** + *

Sets the type of shape used to draw the gradient.

+ *

Note: changing this property will affect all instances + * of a drawable loaded from a resource. It is recommended to invoke + * {@link #mutate()} before changing this property.

+ * + * @param shape The desired shape for this drawable: {@link #LINE}, + * {@link #OVAL}, {@link #RECTANGLE} or {@link #RING} + * + * @see #mutate() + */ + public void setShape(int shape) { + mRingPath = null; + mPathIsDirty = true; + mGradientState.setShape(shape); + invalidateSelf(); + } + + /** + *

Sets the type of gradient used by this drawable..

+ *

Note: changing this property will affect all instances + * of a drawable loaded from a resource. It is recommended to invoke + * {@link #mutate()} before changing this property.

+ * + * @param gradient The type of the gradient: {@link #LINEAR_GRADIENT}, + * {@link #RADIAL_GRADIENT} or {@link #SWEEP_GRADIENT} + * + * @see #mutate() + */ + public void setGradientType(int gradient) { + mGradientState.setGradientType(gradient); + mRectIsDirty = true; + invalidateSelf(); + } + + /** + *

Sets the center location of the gradient. The radius is honored only when + * the gradient type is set to {@link #RADIAL_GRADIENT} or {@link #SWEEP_GRADIENT}.

+ *

Note: changing this property will affect all instances + * of a drawable loaded from a resource. It is recommended to invoke + * {@link #mutate()} before changing this property.

+ * + * @param x The x coordinate of the gradient's center + * @param y The y coordinate of the gradient's center + * + * @see #mutate() + * @see #setGradientType(int) + */ + public void setGradientCenter(float x, float y) { + mGradientState.setGradientCenter(x, y); + mRectIsDirty = true; + invalidateSelf(); + } + + /** + *

Sets the radius of the gradient. The radius is honored only when the + * gradient type is set to {@link #RADIAL_GRADIENT}.

+ *

Note: changing this property will affect all instances + * of a drawable loaded from a resource. It is recommended to invoke + * {@link #mutate()} before changing this property.

+ * + * @param gradientRadius The radius of the gradient in pixels + * + * @see #mutate() + * @see #setGradientType(int) + */ + public void setGradientRadius(float gradientRadius) { + mGradientState.setGradientRadius(gradientRadius); + mRectIsDirty = true; + invalidateSelf(); + } + + /** + *

Sets whether or not this drawable will honor its level + * property.

+ *

Note: changing this property will affect all instances + * of a drawable loaded from a resource. It is recommended to invoke + * {@link #mutate()} before changing this property.

+ * + * @param useLevel True if this drawable should honor its level, false otherwise + * + * @see #mutate() + * @see #setLevel(int) + * @see #getLevel() + */ + public void setUseLevel(boolean useLevel) { + mGradientState.mUseLevel = useLevel; + mRectIsDirty = true; + invalidateSelf(); + } + + private int modulateAlpha(int alpha) { + int scale = mAlpha + (mAlpha >> 7); + return alpha * scale >> 8; + } + + /** + * Returns the orientation of the gradient defined in this drawable. + */ + public Orientation getOrientation() { + return mGradientState.mOrientation; + } + + /** + *

Changes the orientation of the gradient defined in this drawable.

+ *

Note: changing orientation will affect all instances + * of a drawable loaded from a resource. It is recommended to invoke + * {@link #mutate()} before changing the orientation.

+ * + * @param orientation The desired orientation (angle) of the gradient + * + * @see #mutate() + */ + public void setOrientation(Orientation orientation) { + mGradientState.mOrientation = orientation; + mRectIsDirty = true; + invalidateSelf(); + } + + /** + *

Sets the colors used to draw the gradient. Each color is specified as an + * ARGB integer and the array must contain at least 2 colors.

+ *

Note: changing orientation will affect all instances + * of a drawable loaded from a resource. It is recommended to invoke + * {@link #mutate()} before changing the orientation.

+ * + * @param colors 2 or more ARGB colors + * + * @see #mutate() + * @see #setColor(int) + */ + public void setColors(int[] colors) { + mGradientState.setColors(colors); + mRectIsDirty = true; + invalidateSelf(); + } + + @Override + public void draw(Canvas canvas) { + if (!ensureValidRect()) { + // nothing to draw + return; + } + + // remember the alpha values, in case we temporarily overwrite them + // when we modulate them with mAlpha + final int prevFillAlpha = mFillPaint.getAlpha(); + final int prevStrokeAlpha = mStrokePaint != null ? mStrokePaint.getAlpha() : 0; + // compute the modulate alpha values + final int currFillAlpha = modulateAlpha(prevFillAlpha); + final int currStrokeAlpha = modulateAlpha(prevStrokeAlpha); + + final boolean haveStroke = currStrokeAlpha > 0 && mStrokePaint != null && + mStrokePaint.getStrokeWidth() > 0; + final boolean haveFill = currFillAlpha > 0; + final GradientState st = mGradientState; + final ColorFilter colorFilter = mColorFilter != null ? mColorFilter : mTintFilter; + System.out.println("draw(): colorFilter: "+colorFilter); + /* we need a layer iff we're drawing both a fill and stroke, and the + stroke is non-opaque, and our shapetype actually supports + fill+stroke. Otherwise we can just draw the stroke (if any) on top + of the fill (if any) without worrying about blending artifacts. + */ + final boolean useLayer = haveStroke && haveFill && st.mShape != LINE && + currStrokeAlpha < 255 && (mAlpha < 255 || colorFilter != null); + + /* Drawing with a layer is slower than direct drawing, but it + allows us to apply paint effects like alpha and colorfilter to + the result of multiple separate draws. In our case, if the user + asks for a non-opaque alpha value (via setAlpha), and we're + stroking, then we need to apply the alpha AFTER we've drawn + both the fill and the stroke. + */ + /*if (useLayer) { + if (mLayerPaint == null) { + mLayerPaint = new Paint(); + } + mLayerPaint.setDither(mDither); + mLayerPaint.setAlpha(mAlpha); + mLayerPaint.setColorFilter(colorFilter); + + float rad = mStrokePaint.getStrokeWidth(); + canvas.saveLayer(mRect.left - rad, mRect.top - rad, + mRect.right + rad, mRect.bottom + rad, + mLayerPaint, Canvas.HAS_ALPHA_LAYER_SAVE_FLAG); + + // don't perform the filter in our individual paints + // since the layer will do it for us + mFillPaint.setColorFilter(null); + mStrokePaint.setColorFilter(null); + } else {*/ + /* if we're not using a layer, apply the dither/filter to our + individual paints + */ + mFillPaint.setAlpha(currFillAlpha); + mFillPaint.setDither(mDither); + mFillPaint.setColorFilter(colorFilter); + if (colorFilter != null && !mGradientState.mHasSolidColor) { + mFillPaint.setColor(mAlpha << 24); + } + if (haveStroke) { + mStrokePaint.setAlpha(currStrokeAlpha); + mStrokePaint.setDither(mDither); + mStrokePaint.setColorFilter(colorFilter); + } + /*}*/ + + switch (st.mShape) { + case RECTANGLE: + if (st.mRadiusArray != null) { + if (mPathIsDirty || mRectIsDirty) { + mPath.reset(); + mPath.addRoundRect(mRect, st.mRadiusArray, Path.Direction.CW); + mPathIsDirty = mRectIsDirty = false; + } + canvas.drawPath(mPath, mFillPaint); + if (haveStroke) { + canvas.drawPath(mPath, mStrokePaint); + } + } else if (st.mRadius > 0.0f) { + // since the caller is only giving us 1 value, we will force + // it to be square if the rect is too small in one dimension + // to show it. If we did nothing, Skia would clamp the rad + // independently along each axis, giving us a thin ellipse + // if the rect were very wide but not very tall + float rad = st.mRadius; + float r = Math.min(mRect.width(), mRect.height()) * 0.5f; + if (rad > r) { + rad = r; + } + canvas.drawRoundRect(mRect, rad, rad, mFillPaint); + if (haveStroke) { + canvas.drawRoundRect(mRect, rad, rad, mStrokePaint); + } + } else { + if (mFillPaint.getColor() != 0 || colorFilter != null || + mFillPaint.getShader() != null) { + canvas.drawRect(mRect, mFillPaint); + } + if (haveStroke) { + canvas.drawRect(mRect, mStrokePaint); + } + } + break; + case OVAL: + /*canvas.drawOval(mRect, mFillPaint); + if (haveStroke) { + canvas.drawOval(mRect, mStrokePaint); + }*/ + break; + case LINE: { + RectF r = mRect; + float y = r.centerY(); + canvas.drawLine(r.left, y, r.right, y, mStrokePaint); + break; + } + case RING: + Path path = buildRing(st); + canvas.drawPath(path, mFillPaint); + if (haveStroke) { + canvas.drawPath(path, mStrokePaint); + } + break; + } + + if (useLayer) { + canvas.restore(); + } else { + mFillPaint.setAlpha(prevFillAlpha); + if (haveStroke) { + mStrokePaint.setAlpha(prevStrokeAlpha); + } + } + } + + private Path buildRing(GradientState st) { + if (mRingPath != null && (!st.mUseLevelForShape || !mPathIsDirty)) + return mRingPath; + mPathIsDirty = false; + + float sweep = st.mUseLevelForShape ? (360.0f * getLevel() / 10000.0f) : 360f; + + RectF bounds = new RectF(mRect); + + float x = bounds.width() / 2.0f; + float y = bounds.height() / 2.0f; + + float thickness = st.mThickness != -1 ? st.mThickness : bounds.width() / st.mThicknessRatio; + // inner radius + float radius = st.mInnerRadius != -1 ? st.mInnerRadius : bounds.width() / st.mInnerRadiusRatio; + + RectF innerBounds = new RectF(bounds); + innerBounds.inset(x - radius, y - radius); + + bounds = new RectF(innerBounds); + bounds.inset(-thickness, -thickness); + + if (mRingPath == null) { + mRingPath = new Path(); + } else { + mRingPath.reset(); + } + + final Path ringPath = mRingPath; + // arcTo treats the sweep angle mod 360, so check for that, since we + // think 360 means draw the entire oval + if (sweep < 360 && sweep > -360) { + ringPath.setFillType(Path.FillType.EVEN_ODD); + // inner top + ringPath.moveTo(x + radius, y); + // outer top + ringPath.lineTo(x + radius + thickness, y); + // outer arc + ringPath.arcTo(bounds, 0.0f, sweep, false); + // inner arc + ringPath.arcTo(innerBounds, sweep, -sweep, false); + ringPath.close(); + } else { + // add the entire ovals + ringPath.addOval(bounds, Path.Direction.CW); + ringPath.addOval(innerBounds, Path.Direction.CCW); + } + + return ringPath; + } + + /** + *

Changes this drawbale to use a single color instead of a gradient.

+ *

Note: changing color will affect all instances + * of a drawable loaded from a resource. It is recommended to invoke + * {@link #mutate()} before changing the color.

+ * + * @param argb The color used to fill the shape + * + * @see #mutate() + * @see #setColors(int[]) + */ + public void setColor(int argb) { + mGradientState.setSolidColor(argb); + mFillPaint.setColor(argb); + invalidateSelf(); + } + + @Override + public int getChangingConfigurations() { + return super.getChangingConfigurations() | mGradientState.mChangingConfigurations; + } + + @Override + public void setAlpha(int alpha) { + if (alpha != mAlpha) { + mAlpha = alpha; + invalidateSelf(); + } + } + + //@Override + public int getAlpha() { + return mAlpha; + } + + //@Override + public void setDither(boolean dither) { + if (dither != mDither) { + mDither = dither; + invalidateSelf(); + } + } + + @Override + public void setColorFilter(ColorFilter cf) { + if (cf != mColorFilter) { + mColorFilter = cf; + invalidateSelf(); + } + } + + @Override + public void setTintList(ColorStateList tint) { + mGradientState.mTint = tint; + mTintFilter = updateTintFilter(mTintFilter, tint, mGradientState.mTintMode); + invalidateSelf(); + } + + @Override + public void setTintMode(PorterDuff.Mode tintMode) { + mGradientState.mTintMode = tintMode; + mTintFilter = updateTintFilter(mTintFilter, mGradientState.mTint, tintMode); + invalidateSelf(); + } + + //@Override + public int getOpacity() { + return mGradientState.mOpaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT; + } + + @Override + protected void onBoundsChange(Rect r) { + super.onBoundsChange(r); + mRingPath = null; + mPathIsDirty = true; + mRectIsDirty = true; + } + + //@Override + protected boolean onLevelChange(int level) { + //super.onLevelChange(level); + mRectIsDirty = true; + mPathIsDirty = true; + invalidateSelf(); + return true; + } + + /** + * This checks mRectIsDirty, and if it is true, recomputes both our drawing + * rectangle (mRect) and the gradient itself, since it depends on our + * rectangle too. + * @return true if the resulting rectangle is not empty, false otherwise + */ + private boolean ensureValidRect() { + if (mRectIsDirty) { + mRectIsDirty = false; + + Rect bounds = getBounds(); + float inset = 0; + + if (mStrokePaint != null) { + inset = mStrokePaint.getStrokeWidth() * 0.5f; + } + + final GradientState st = mGradientState; + + mRect.set(bounds.left + inset, bounds.top + inset, + bounds.right - inset, bounds.bottom - inset); + + final int[] colors = st.mColors; + if (colors != null) { + RectF r = mRect; + float x0, x1, y0, y1; + + if (st.mGradient == LINEAR_GRADIENT) { + final float level = st.mUseLevel ? (float)getLevel() / 10000.0f : 1.0f; + switch (st.mOrientation) { + case TOP_BOTTOM: + x0 = r.left; + y0 = r.top; + x1 = x0; + y1 = level * r.bottom; + break; + case TR_BL: + x0 = r.right; + y0 = r.top; + x1 = level * r.left; + y1 = level * r.bottom; + break; + case RIGHT_LEFT: + x0 = r.right; + y0 = r.top; + x1 = level * r.left; + y1 = y0; + break; + case BR_TL: + x0 = r.right; + y0 = r.bottom; + x1 = level * r.left; + y1 = level * r.top; + break; + case BOTTOM_TOP: + x0 = r.left; + y0 = r.bottom; + x1 = x0; + y1 = level * r.top; + break; + case BL_TR: + x0 = r.left; + y0 = r.bottom; + x1 = level * r.right; + y1 = level * r.top; + break; + case LEFT_RIGHT: + x0 = r.left; + y0 = r.top; + x1 = level * r.right; + y1 = y0; + break; + default: /* TL_BR */ + x0 = r.left; + y0 = r.top; + x1 = level * r.right; + y1 = level * r.bottom; + break; + } + + mFillPaint.setShader(new LinearGradient(x0, y0, x1, y1, + colors, st.mPositions, Shader.TileMode.CLAMP)); + } else if (st.mGradient == RADIAL_GRADIENT) { + x0 = r.left + (r.right - r.left) * st.mCenterX; + y0 = r.top + (r.bottom - r.top) * st.mCenterY; + + final float level = st.mUseLevel ? (float)getLevel() / 10000.0f : 1.0f; + + mFillPaint.setShader(new RadialGradient(x0, y0, + level * st.mGradientRadius, colors, null, + Shader.TileMode.CLAMP)); + } else if (st.mGradient == SWEEP_GRADIENT) { + /*x0 = r.left + (r.right - r.left) * st.mCenterX; + y0 = r.top + (r.bottom - r.top) * st.mCenterY; + + int[] tempColors = colors; + float[] tempPositions = null; + + if (st.mUseLevel) { + tempColors = st.mTempColors; + final int length = colors.length; + if (tempColors == null || tempColors.length != length + 1) { + tempColors = st.mTempColors = new int[length + 1]; + } + System.arraycopy(colors, 0, tempColors, 0, length); + tempColors[length] = colors[length - 1]; + + tempPositions = st.mTempPositions; + final float fraction = 1.0f / (float)(length - 1); + if (tempPositions == null || tempPositions.length != length + 1) { + tempPositions = st.mTempPositions = new float[length + 1]; + } + + final float level = (float)getLevel() / 10000.0f; + for (int i = 0; i < length; i++) { + tempPositions[i] = i * fraction * level; + } + tempPositions[length] = 1.0f; + } + mFillPaint.setShader(new SweepGradient(x0, y0, tempColors, tempPositions));*/ + } + + // If we don't have a solid color, the alpha channel must be + // maxed out so that alpha modulation works correctly. + if (!st.mHasSolidColor) { + mFillPaint.setColor(Color.BLACK); + } + } + } + return !mRect.isEmpty(); + } + +/* @Override + public void inflate(Resources r, XmlPullParser parser, + AttributeSet attrs) + throws XmlPullParserException, IOException { + + final GradientState st = mGradientState; + + TypedArray a = r.obtainAttributes(attrs, + com.android.internal.R.styleable.GradientDrawable); + + super.inflateWithAttributes(r, parser, a, + com.android.internal.R.styleable.GradientDrawable_visible); + + int shapeType = a.getInt( + com.android.internal.R.styleable.GradientDrawable_shape, RECTANGLE); + boolean dither = a.getBoolean( + com.android.internal.R.styleable.GradientDrawable_dither, false); + + if (shapeType == RING) { + st.mInnerRadius = a.getDimensionPixelSize( + com.android.internal.R.styleable.GradientDrawable_innerRadius, -1); + if (st.mInnerRadius == -1) { + st.mInnerRadiusRatio = a.getFloat( + com.android.internal.R.styleable.GradientDrawable_innerRadiusRatio, 3.0f); + } + st.mThickness = a.getDimensionPixelSize( + com.android.internal.R.styleable.GradientDrawable_thickness, -1); + if (st.mThickness == -1) { + st.mThicknessRatio = a.getFloat( + com.android.internal.R.styleable.GradientDrawable_thicknessRatio, 9.0f); + } + st.mUseLevelForShape = a.getBoolean( + com.android.internal.R.styleable.GradientDrawable_useLevel, true); + } + + a.recycle(); + + setShape(shapeType); + setDither(dither); + + int type; + + final int innerDepth = parser.getDepth() + 1; + int depth; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) { + if (type != XmlPullParser.START_TAG) { + continue; + } + + if (depth > innerDepth) { + continue; + } + + String name = parser.getName(); + + if (name.equals("size")) { + a = r.obtainAttributes(attrs, + com.android.internal.R.styleable.GradientDrawableSize); + int width = a.getDimensionPixelSize( + com.android.internal.R.styleable.GradientDrawableSize_width, -1); + int height = a.getDimensionPixelSize( + com.android.internal.R.styleable.GradientDrawableSize_height, -1); + a.recycle(); + setSize(width, height); + } else if (name.equals("gradient")) { + a = r.obtainAttributes(attrs, + com.android.internal.R.styleable.GradientDrawableGradient); + int startColor = a.getColor( + com.android.internal.R.styleable.GradientDrawableGradient_startColor, 0); + boolean hasCenterColor = a + .hasValue(com.android.internal.R.styleable.GradientDrawableGradient_centerColor); + int centerColor = a.getColor( + com.android.internal.R.styleable.GradientDrawableGradient_centerColor, 0); + int endColor = a.getColor( + com.android.internal.R.styleable.GradientDrawableGradient_endColor, 0); + int gradientType = a.getInt( + com.android.internal.R.styleable.GradientDrawableGradient_type, + LINEAR_GRADIENT); + + st.mCenterX = getFloatOrFraction( + a, + com.android.internal.R.styleable.GradientDrawableGradient_centerX, + 0.5f); + + st.mCenterY = getFloatOrFraction( + a, + com.android.internal.R.styleable.GradientDrawableGradient_centerY, + 0.5f); + + st.mUseLevel = a.getBoolean( + com.android.internal.R.styleable.GradientDrawableGradient_useLevel, false); + st.mGradient = gradientType; + + if (gradientType == LINEAR_GRADIENT) { + int angle = (int)a.getFloat( + com.android.internal.R.styleable.GradientDrawableGradient_angle, 0); + angle %= 360; + if (angle % 45 != 0) { + throw new XmlPullParserException(a.getPositionDescription() + " tag requires 'angle' attribute to " + + "be a multiple of 45"); + } + + switch (angle) { + case 0: + st.mOrientation = Orientation.LEFT_RIGHT; + break; + case 45: + st.mOrientation = Orientation.BL_TR; + break; + case 90: + st.mOrientation = Orientation.BOTTOM_TOP; + break; + case 135: + st.mOrientation = Orientation.BR_TL; + break; + case 180: + st.mOrientation = Orientation.RIGHT_LEFT; + break; + case 225: + st.mOrientation = Orientation.TR_BL; + break; + case 270: + st.mOrientation = Orientation.TOP_BOTTOM; + break; + case 315: + st.mOrientation = Orientation.TL_BR; + break; + } + } else { + TypedValue tv = a.peekValue( + com.android.internal.R.styleable.GradientDrawableGradient_gradientRadius); + if (tv != null) { + boolean radiusRel = tv.type == TypedValue.TYPE_FRACTION; + st.mGradientRadius = radiusRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat(); + } else if (gradientType == RADIAL_GRADIENT) { + throw new XmlPullParserException( + a.getPositionDescription() + " tag requires 'gradientRadius' " + + "attribute with radial type"); + } + } + + a.recycle(); + + if (hasCenterColor) { + st.mColors = new int[3]; + st.mColors[0] = startColor; + st.mColors[1] = centerColor; + st.mColors[2] = endColor; + + st.mPositions = new float[3]; + st.mPositions[0] = 0.0f; + // Since 0.5f is default value, try to take the one that isn't 0.5f + st.mPositions[1] = st.mCenterX != 0.5f ? st.mCenterX : st.mCenterY; + st.mPositions[2] = 1f; + } else { + st.mColors = new int[2]; + st.mColors[0] = startColor; + st.mColors[1] = endColor; + } + + } else if (name.equals("solid")) { + a = r.obtainAttributes(attrs, + com.android.internal.R.styleable.GradientDrawableSolid); + int argb = a.getColor( + com.android.internal.R.styleable.GradientDrawableSolid_color, 0); + a.recycle(); + setColor(argb); + } else if (name.equals("stroke")) { + a = r.obtainAttributes(attrs, + com.android.internal.R.styleable.GradientDrawableStroke); + int width = a.getDimensionPixelSize( + com.android.internal.R.styleable.GradientDrawableStroke_width, 0); + int color = a.getColor( + com.android.internal.R.styleable.GradientDrawableStroke_color, 0); + float dashWidth = a.getDimension( + com.android.internal.R.styleable.GradientDrawableStroke_dashWidth, 0); + if (dashWidth != 0.0f) { + float dashGap = a.getDimension( + com.android.internal.R.styleable.GradientDrawableStroke_dashGap, 0); + setStroke(width, color, dashWidth, dashGap); + } else { + setStroke(width, color); + } + a.recycle(); + } else if (name.equals("corners")) { + a = r.obtainAttributes(attrs, + com.android.internal.R.styleable.DrawableCorners); + int radius = a.getDimensionPixelSize( + com.android.internal.R.styleable.DrawableCorners_radius, 0); + setCornerRadius(radius); + int topLeftRadius = a.getDimensionPixelSize( + com.android.internal.R.styleable.DrawableCorners_topLeftRadius, radius); + int topRightRadius = a.getDimensionPixelSize( + com.android.internal.R.styleable.DrawableCorners_topRightRadius, radius); + int bottomLeftRadius = a.getDimensionPixelSize( + com.android.internal.R.styleable.DrawableCorners_bottomLeftRadius, radius); + int bottomRightRadius = a.getDimensionPixelSize( + com.android.internal.R.styleable.DrawableCorners_bottomRightRadius, radius); + if (topLeftRadius != radius || topRightRadius != radius || + bottomLeftRadius != radius || bottomRightRadius != radius) { + // The corner radii are specified in clockwise order (see Path.addRoundRect()) + setCornerRadii(new float[] { + topLeftRadius, topLeftRadius, + topRightRadius, topRightRadius, + bottomRightRadius, bottomRightRadius, + bottomLeftRadius, bottomLeftRadius}); + } + a.recycle(); + } else if (name.equals("padding")) { + a = r.obtainAttributes(attrs, + com.android.internal.R.styleable.GradientDrawablePadding); + mPadding = new Rect( + a.getDimensionPixelOffset( + com.android.internal.R.styleable.GradientDrawablePadding_left, 0), + a.getDimensionPixelOffset( + com.android.internal.R.styleable.GradientDrawablePadding_top, 0), + a.getDimensionPixelOffset( + com.android.internal.R.styleable.GradientDrawablePadding_right, 0), + a.getDimensionPixelOffset( + com.android.internal.R.styleable.GradientDrawablePadding_bottom, 0)); + a.recycle(); + mGradientState.mPadding = mPadding; + } else { + Log.w("drawable", "Bad element under : " + name); + } + } + + mGradientState.computeOpacity(); + }*/ + + private static float getFloatOrFraction(TypedArray a, int index, float defaultValue) { + TypedValue tv = a.peekValue(index); + float v = defaultValue; + if (tv != null) { + boolean vIsFraction = tv.type == TypedValue.TYPE_FRACTION; + v = vIsFraction ? tv.getFraction(1.0f, 1.0f) : tv.getFloat(); + } + return v; + } + + @Override + public int getIntrinsicWidth() { + return mGradientState.mWidth; + } + + @Override + public int getIntrinsicHeight() { + return mGradientState.mHeight; + } + + @Override + public ConstantState getConstantState() { + mGradientState.mChangingConfigurations = getChangingConfigurations(); + 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 int[] mTempColors; // no need to copy + public float[] mTempPositions; // no need to copy + 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 mInnerRadiusRatio; + public float mThicknessRatio; + public int mInnerRadius; + public int mThickness; + private float mCenterX = 0.5f; + private float mCenterY = 0.5f; + private float mGradientRadius = 0.5f; + private boolean mUseLevel; + private boolean mUseLevelForShape; + private boolean mOpaque; + + ColorStateList mTint = null; + PorterDuff.Mode mTintMode = DEFAULT_TINT_MODE; + + GradientState(Orientation orientation, int[] colors) { + mOrientation = orientation; + setColors(colors); + } + + public GradientState(GradientState state) { + mChangingConfigurations = state.mChangingConfigurations; + mShape = state.mShape; + mGradient = state.mGradient; + mOrientation = state.mOrientation; + if (state.mColors != null) { + mColors = state.mColors.clone(); + } + if (state.mPositions != null) { + mPositions = state.mPositions.clone(); + } + mHasSolidColor = state.mHasSolidColor; + mSolidColor = state.mSolidColor; + mStrokeWidth = state.mStrokeWidth; + mStrokeColor = state.mStrokeColor; + mStrokeDashWidth = state.mStrokeDashWidth; + mStrokeDashGap = state.mStrokeDashGap; + mRadius = state.mRadius; + if (state.mRadiusArray != null) { + mRadiusArray = state.mRadiusArray.clone(); + } + if (state.mPadding != null) { + mPadding = new Rect(state.mPadding); + } + mWidth = state.mWidth; + mHeight = state.mHeight; + mInnerRadiusRatio = state.mInnerRadiusRatio; + mThicknessRatio = state.mThicknessRatio; + mInnerRadius = state.mInnerRadius; + mThickness = state.mThickness; + mCenterX = state.mCenterX; + mCenterY = state.mCenterY; + mGradientRadius = state.mGradientRadius; + mUseLevel = state.mUseLevel; + mUseLevelForShape = state.mUseLevelForShape; + mOpaque = state.mOpaque; + + mTint = state.mTint; + mTintMode = state.mTintMode; + } + + @Override + public Drawable newDrawable() { + return new GradientDrawable(this); + } + + @Override + public Drawable newDrawable(Resources res) { + return new GradientDrawable(this); + } + + //@Override + public int getChangingConfigurations() { + return mChangingConfigurations; + } + + public void setShape(int shape) { + mShape = shape; + computeOpacity(); + } + + public void setGradientType(int gradient) { + mGradient = gradient; + } + + public void setGradientCenter(float x, float y) { + mCenterX = x; + mCenterY = y; + } + + public void setColors(int[] colors) { + mHasSolidColor = false; + mColors = colors; + computeOpacity(); + } + + public void setSolidColor(int argb) { + mHasSolidColor = true; + mSolidColor = argb; + mColors = null; + computeOpacity(); + } + + private void computeOpacity() { + if (mShape != RECTANGLE) { + mOpaque = false; + return; + } + + if (mRadius > 0 || mRadiusArray != null) { + mOpaque = false; + return; + } + + if (mStrokeWidth > 0 && !isOpaque(mStrokeColor)) { + mOpaque = false; + return; + } + + if (mHasSolidColor) { + mOpaque = isOpaque(mSolidColor); + return; + } + + if (mColors != null) { + for (int i = 0; i < mColors.length; i++) { + if (!isOpaque(mColors[i])) { + mOpaque = false; + return; + } + } + } + + mOpaque = true; + } + + private static boolean isOpaque(int color) { + return ((color >> 24) & 0xff) == 0xff; + } + + public void setStroke(int width, int color) { + mStrokeWidth = width; + mStrokeColor = color; + computeOpacity(); + } + + public void setStroke(int width, int color, float dashWidth, float dashGap) { + mStrokeWidth = width; + mStrokeColor = color; + mStrokeDashWidth = dashWidth; + mStrokeDashGap = dashGap; + computeOpacity(); + } + + public void setCornerRadius(float radius) { + if (radius < 0) { + radius = 0; + } + mRadius = radius; + mRadiusArray = null; + } + + public void setCornerRadii(float[] radii) { + mRadiusArray = radii; + if (radii == null) { + mRadius = 0; + } + } + + public void setSize(int width, int height) { + mWidth = width; + mHeight = height; + } + + public void setGradientRadius(float gradientRadius) { + mGradientRadius = gradientRadius; + } + } + + private GradientDrawable(GradientState state) { + mGradientState = state; + initializeWithState(state); + mRectIsDirty = true; + mMutated = false; + } + + private void initializeWithState(GradientState state) { + if (state.mHasSolidColor) { + mFillPaint.setColor(state.mSolidColor); + } else if (state.mColors == null) { + // If we don't have a solid color and we don't have a gradient, + // the app is stroking the shape, set the color to the default + // value of state.mSolidColor + mFillPaint.setColor(0); + } else { + // Otherwise, make sure the fill alpha is maxed out. + mFillPaint.setColor(Color.BLACK); + } + mPadding = state.mPadding; + if (state.mStrokeWidth >= 0) { + mStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mStrokePaint.setStyle(Paint.Style.STROKE); + mStrokePaint.setStrokeWidth(state.mStrokeWidth); + mStrokePaint.setColor(state.mStrokeColor); + + if (state.mStrokeDashWidth != 0.0f) { + DashPathEffect e = new DashPathEffect( + new float[] {state.mStrokeDashWidth, state.mStrokeDashGap}, 0); + mStrokePaint.setPathEffect(e); + } + } + } } diff --git a/src/api-impl/android/telephony/SubscriptionManager.java b/src/api-impl/android/telephony/SubscriptionManager.java new file mode 100644 index 00000000..d15f1266 --- /dev/null +++ b/src/api-impl/android/telephony/SubscriptionManager.java @@ -0,0 +1,5 @@ +package android.telephony; + +public class SubscriptionManager { + +} diff --git a/src/api-impl/meson.build b/src/api-impl/meson.build index f31bae25..b20a9a1e 100644 --- a/src/api-impl/meson.build +++ b/src/api-impl/meson.build @@ -48,6 +48,7 @@ hax_jar = jar('hax', [ 'android/app/admin/DevicePolicyManager.java', 'android/app/job/JobScheduler.java', 'android/app/job/JobService.java', + 'android/app/usage/UsageStatsManager.java', 'android/appwidget/AppWidgetManager.java', 'android/bluetooth/BluetoothManager.java', 'android/bluetooth/le/ScanCallback.java', @@ -175,6 +176,7 @@ hax_jar = jar('hax', [ 'android/graphics/Path.java', 'android/graphics/PathEffect.java', 'android/graphics/PathMeasure.java', + 'android/graphics/PixelFormat.java', 'android/graphics/Point.java', 'android/graphics/PointF.java', 'android/graphics/PorterDuff.java', @@ -297,6 +299,7 @@ hax_jar = jar('hax', [ 'android/provider/Settings.java', 'android/telecom/TelecomManager.java', 'android/telephony/PhoneStateListener.java', + 'android/telephony/SubscriptionManager.java', 'android/telephony/TelephonyManager.java', 'android/text/ClipboardManager.java', 'android/text/Editable.java',