Fix NinePatchDrawable handling of density changes
Scaling is now manually applied when the canvas density is not set.
Removes set/getNinePatch accessors that were added in N, since these
are not used and setting the nine patch directly will break padding.
Also removes local NinePatch, which was not necessary.
Bug: 27038114
Change-Id: Ie8b2e485b54d1ed1521081b329a09915fd0a95c1
diff --git a/api/current.txt b/api/current.txt
index 66c1d39..a01c420 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11947,6 +11947,8 @@
ctor public Outline(android.graphics.Outline);
method public boolean canClip();
method public float getAlpha();
+ method public float getRadius();
+ method public boolean getRect(android.graphics.Rect);
method public boolean isEmpty();
method public void offset(int, int);
method public void set(android.graphics.Outline);
@@ -12974,12 +12976,10 @@
ctor public deprecated NinePatchDrawable(android.graphics.NinePatch);
ctor public NinePatchDrawable(android.content.res.Resources, android.graphics.NinePatch);
method public void draw(android.graphics.Canvas);
- method public android.graphics.NinePatch getNinePatch();
method public int getOpacity();
method public android.graphics.Paint getPaint();
method public void setAlpha(int);
method public void setColorFilter(android.graphics.ColorFilter);
- method public void setNinePatch(android.graphics.NinePatch);
method public void setTargetDensity(android.graphics.Canvas);
method public void setTargetDensity(android.util.DisplayMetrics);
method public void setTargetDensity(int);
diff --git a/api/system-current.txt b/api/system-current.txt
index 11e5af5..d4e6d2f 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -12357,6 +12357,8 @@
ctor public Outline(android.graphics.Outline);
method public boolean canClip();
method public float getAlpha();
+ method public float getRadius();
+ method public boolean getRect(android.graphics.Rect);
method public boolean isEmpty();
method public void offset(int, int);
method public void set(android.graphics.Outline);
@@ -13384,12 +13386,10 @@
ctor public deprecated NinePatchDrawable(android.graphics.NinePatch);
ctor public NinePatchDrawable(android.content.res.Resources, android.graphics.NinePatch);
method public void draw(android.graphics.Canvas);
- method public android.graphics.NinePatch getNinePatch();
method public int getOpacity();
method public android.graphics.Paint getPaint();
method public void setAlpha(int);
method public void setColorFilter(android.graphics.ColorFilter);
- method public void setNinePatch(android.graphics.NinePatch);
method public void setTargetDensity(android.graphics.Canvas);
method public void setTargetDensity(android.util.DisplayMetrics);
method public void setTargetDensity(int);
diff --git a/api/test-current.txt b/api/test-current.txt
index a7bc720..6d85eaa 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -11955,6 +11955,8 @@
ctor public Outline(android.graphics.Outline);
method public boolean canClip();
method public float getAlpha();
+ method public float getRadius();
+ method public boolean getRect(android.graphics.Rect);
method public boolean isEmpty();
method public void offset(int, int);
method public void set(android.graphics.Outline);
@@ -12982,12 +12984,10 @@
ctor public deprecated NinePatchDrawable(android.graphics.NinePatch);
ctor public NinePatchDrawable(android.content.res.Resources, android.graphics.NinePatch);
method public void draw(android.graphics.Canvas);
- method public android.graphics.NinePatch getNinePatch();
method public int getOpacity();
method public android.graphics.Paint getPaint();
method public void setAlpha(int);
method public void setColorFilter(android.graphics.ColorFilter);
- method public void setNinePatch(android.graphics.NinePatch);
method public void setTargetDensity(android.graphics.Canvas);
method public void setTargetDensity(android.util.DisplayMetrics);
method public void setTargetDensity(int);
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index aa40408..99fa9fe 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -18,6 +18,7 @@
import android.annotation.FloatRange;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.graphics.drawable.Drawable;
/**
@@ -176,6 +177,34 @@
}
/**
+ * Populates {@code outBounds} with the outline bounds, if set, and returns
+ * {@code true}. If no outline bounds are set, or if a path has been set
+ * via {@link #setConvexPath(Path)}, returns {@code false}.
+ *
+ * @param outRect the rect to populate with the outline bounds, if set
+ * @return {@code true} if {@code outBounds} was populated with outline
+ * bounds, or {@code false} if no outline bounds are set
+ */
+ public boolean getRect(@NonNull Rect outRect) {
+ if (mRect == null) {
+ return false;
+ }
+ outRect.set(mRect);
+ return true;
+ }
+
+ /**
+ * Returns the rounded rect radius, if set, or {@code -1} if a path has
+ * been set via {@link #setConvexPath(Path)}. A return value of {@code 0}
+ * indicates a non-rounded rect.
+ *
+ * @return the rounded rect radius or {@code -1}
+ */
+ public float getRadius() {
+ return mRadius;
+ }
+
+ /**
* Sets the outline to the oval defined by input rect.
*/
public void setOval(int left, int top, int right, int bottom) {
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index bfbdfa5..6816539 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -66,11 +66,16 @@
public class NinePatchDrawable extends Drawable {
// dithering helps a lot, and is pretty cheap, so default is true
private static final boolean DEFAULT_DITHER = false;
+
+ /** Temporary rect used for density scaling. */
+ private Rect mTempRect;
+
private NinePatchState mNinePatchState;
- private NinePatch mNinePatch;
private PorterDuffColorFilter mTintFilter;
private Rect mPadding;
private Insets mOpticalInsets = Insets.NONE;
+ private Rect mOutlineInsets;
+ private float mOutlineRadius;
private Paint mPaint;
private boolean mMutated;
@@ -86,8 +91,9 @@
/**
* Create drawable from raw nine-patch data, not dealing with density.
+ *
* @deprecated Use {@link #NinePatchDrawable(Resources, Bitmap, byte[], Rect, String)}
- * to ensure that the drawable has correctly set its target density.
+ * to ensure that the drawable has correctly set its target density.
*/
@Deprecated
public NinePatchDrawable(Bitmap bitmap, byte[] chunk, Rect padding, String srcName) {
@@ -101,7 +107,6 @@
public NinePatchDrawable(Resources res, Bitmap bitmap, byte[] chunk,
Rect padding, String srcName) {
this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), res);
- mNinePatchState.mTargetDensity = mTargetDensity;
}
/**
@@ -114,16 +119,17 @@
Rect padding, Rect opticalInsets, String srcName) {
this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding, opticalInsets),
res);
- mNinePatchState.mTargetDensity = mTargetDensity;
}
/**
* Create drawable from existing nine-patch, not dealing with density.
+ *
* @deprecated Use {@link #NinePatchDrawable(Resources, NinePatch)}
- * to ensure that the drawable has correctly set its target density.
+ * to ensure that the drawable has correctly set its target
+ * density.
*/
@Deprecated
- public NinePatchDrawable(NinePatch patch) {
+ public NinePatchDrawable(@NonNull NinePatch patch) {
this(new NinePatchState(patch, new Rect()), null);
}
@@ -131,9 +137,8 @@
* Create drawable from existing nine-patch, setting initial target density
* based on the display metrics of the resources.
*/
- public NinePatchDrawable(Resources res, NinePatch patch) {
+ public NinePatchDrawable(@Nullable Resources res, @NonNull NinePatch patch) {
this(new NinePatchState(patch, new Rect()), res);
- mNinePatchState.mTargetDensity = mTargetDensity;
}
/**
@@ -146,7 +151,7 @@
* @see android.graphics.Bitmap#setDensity(int)
* @see android.graphics.Bitmap#getDensity()
*/
- public void setTargetDensity(Canvas canvas) {
+ public void setTargetDensity(@NonNull Canvas canvas) {
setTargetDensity(canvas.getDensity());
}
@@ -158,7 +163,7 @@
* @see android.graphics.Bitmap#setDensity(int)
* @see android.graphics.Bitmap#getDensity()
*/
- public void setTargetDensity(DisplayMetrics metrics) {
+ public void setTargetDensity(@NonNull DisplayMetrics metrics) {
setTargetDensity(metrics.densityDpi);
}
@@ -171,78 +176,24 @@
* @see android.graphics.Bitmap#getDensity()
*/
public void setTargetDensity(int density) {
- if (density != mTargetDensity) {
- mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
- if (mNinePatch != null) {
- computeBitmapSize();
- }
+ if (density == 0) {
+ density = DisplayMetrics.DENSITY_DEFAULT;
+ }
+
+ if (mTargetDensity != density) {
+ mTargetDensity = density;
+
+ computeBitmapSize();
invalidateSelf();
}
}
- private static Insets scaleFromDensity(Insets insets, int sdensity, int tdensity) {
- int left = Drawable.scaleFromDensity(insets.left, sdensity, tdensity, true);
- int top = Drawable.scaleFromDensity(insets.top, sdensity, tdensity, true);
- int right = Drawable.scaleFromDensity(insets.right, sdensity, tdensity, true);
- int bottom = Drawable.scaleFromDensity(insets.bottom, sdensity, tdensity, true);
- return Insets.of(left, top, right, bottom);
- }
-
- private void computeBitmapSize() {
- final int sdensity = mNinePatch.getDensity();
- final int tdensity = mTargetDensity;
- if (sdensity == tdensity) {
- mBitmapWidth = mNinePatch.getWidth();
- mBitmapHeight = mNinePatch.getHeight();
- mOpticalInsets = mNinePatchState.mOpticalInsets;
- } else {
- mBitmapWidth = Drawable.scaleFromDensity(
- mNinePatch.getWidth(), sdensity, tdensity, true);
- mBitmapHeight = Drawable.scaleFromDensity(
- mNinePatch.getHeight(), sdensity, tdensity, true);
- if (mNinePatchState.mPadding != null && mPadding != null) {
- Rect dest = mPadding;
- Rect src = mNinePatchState.mPadding;
- if (dest == src) {
- mPadding = dest = new Rect(src);
- }
- dest.left = Drawable.scaleFromDensity(src.left, sdensity, tdensity, true);
- dest.top = Drawable.scaleFromDensity(src.top, sdensity, tdensity, true);
- dest.right = Drawable.scaleFromDensity(src.right, sdensity, tdensity, true);
- dest.bottom = Drawable.scaleFromDensity(src.bottom, sdensity, tdensity, true);
- }
- mOpticalInsets = scaleFromDensity(mNinePatchState.mOpticalInsets, sdensity, tdensity);
- }
- }
-
- /**
- * Sets the nine patch used by this drawable.
- *
- * @param ninePatch the nine patch for this drawable
- */
- public void setNinePatch(NinePatch ninePatch) {
- if (mNinePatch != ninePatch) {
- mNinePatch = ninePatch;
- if (ninePatch != null) {
- computeBitmapSize();
- } else {
- mBitmapWidth = mBitmapHeight = -1;
- mOpticalInsets = Insets.NONE;
- }
- invalidateSelf();
- }
- }
-
- /**
- * @return the nine patch used by this drawable
- */
- public NinePatch getNinePatch() {
- return mNinePatch;
- }
-
@Override
public void draw(Canvas canvas) {
- final Rect bounds = getBounds();
+ final NinePatchState state = mNinePatchState;
+
+ Rect bounds = getBounds();
+ int restoreToCount = -1;
final boolean clearColorFilter;
if (mTintFilter != null && getPaint().getColorFilter() == null) {
@@ -252,22 +203,52 @@
clearColorFilter = false;
}
- final boolean needsMirroring = needsMirroring();
- if (needsMirroring) {
- // Mirror the 9patch
- canvas.translate(bounds.right - bounds.left, 0);
- canvas.scale(-1.0f, 1.0f);
- }
-
final int restoreAlpha;
- if (mNinePatchState.mBaseAlpha != 1.0f) {
- restoreAlpha = mPaint.getAlpha();
- mPaint.setAlpha((int) (restoreAlpha * mNinePatchState.mBaseAlpha + 0.5f));
+ if (state.mBaseAlpha != 1.0f) {
+ restoreAlpha = getPaint().getAlpha();
+ mPaint.setAlpha((int) (restoreAlpha * state.mBaseAlpha + 0.5f));
} else {
restoreAlpha = -1;
}
- mNinePatch.draw(canvas, bounds, mPaint);
+ final boolean needsDensityScaling = canvas.getDensity() == 0;
+ if (needsDensityScaling) {
+ restoreToCount = restoreToCount >= 0 ? restoreToCount : canvas.save();
+
+ // Apply density scaling.
+ final float scale = mTargetDensity / (float) state.mNinePatch.getDensity();
+ final float px = bounds.left;
+ final float py = bounds.top;
+ canvas.scale(scale, scale, px, py);
+
+ if (mTempRect == null) {
+ mTempRect = new Rect();
+ }
+
+ // Scale the bounds to match.
+ final Rect scaledBounds = mTempRect;
+ scaledBounds.left = bounds.left;
+ scaledBounds.top = bounds.top;
+ scaledBounds.right = bounds.left + Math.round(bounds.width() / scale);
+ scaledBounds.bottom = bounds.top + Math.round(bounds.height() / scale);
+ bounds = scaledBounds;
+ }
+
+ final boolean needsMirroring = needsMirroring();
+ if (needsMirroring) {
+ restoreToCount = restoreToCount >= 0 ? restoreToCount : canvas.save();
+
+ // Mirror the 9patch.
+ final float cx = (bounds.left + bounds.right) / 2.0f;
+ final float cy = (bounds.top + bounds.bottom) / 2.0f;
+ canvas.scale(-1.0f, 1.0f, cx, cy);
+ }
+
+ state.mNinePatch.draw(canvas, bounds, mPaint);
+
+ if (restoreToCount >= 0) {
+ canvas.restoreToCount(restoreToCount);
+ }
if (clearColorFilter) {
mPaint.setColorFilter(null);
@@ -284,38 +265,36 @@
}
@Override
- public boolean getPadding(Rect padding) {
- final Rect scaledPadding = mPadding;
- if (scaledPadding != null) {
- if (needsMirroring()) {
- padding.set(scaledPadding.right, scaledPadding.top,
- scaledPadding.left, scaledPadding.bottom);
- } else {
- padding.set(scaledPadding);
- }
+ public boolean getPadding(@NonNull Rect padding) {
+ if (mPadding != null) {
+ padding.set(mPadding);
return (padding.left | padding.top | padding.right | padding.bottom) != 0;
+ } else {
+ return super.getPadding(padding);
}
- return false;
}
@Override
public void getOutline(@NonNull Outline outline) {
final Rect bounds = getBounds();
- if (bounds.isEmpty()) return;
+ if (bounds.isEmpty()) {
+ return;
+ }
- if (mNinePatchState != null) {
- NinePatch.InsetStruct insets = mNinePatchState.mNinePatch.getBitmap().getNinePatchInsets();
+ if (mNinePatchState != null && mOutlineInsets != null) {
+ final NinePatch.InsetStruct insets =
+ mNinePatchState.mNinePatch.getBitmap().getNinePatchInsets();
if (insets != null) {
- final Rect outlineInsets = insets.outlineRect;
- outline.setRoundRect(bounds.left + outlineInsets.left,
- bounds.top + outlineInsets.top,
- bounds.right - outlineInsets.right,
- bounds.bottom - outlineInsets.bottom,
- insets.outlineRadius);
+ outline.setRoundRect(bounds.left + mOutlineInsets.left,
+ bounds.top + mOutlineInsets.top,
+ bounds.right - mOutlineInsets.right,
+ bounds.bottom - mOutlineInsets.bottom,
+ mOutlineRadius);
outline.setAlpha(insets.outlineAlpha * (getAlpha() / 255.0f));
return;
}
}
+
super.getOutline(outline);
}
@@ -324,11 +303,12 @@
*/
@Override
public Insets getOpticalInsets() {
+ final Insets opticalInsets = mOpticalInsets;
if (needsMirroring()) {
- return Insets.of(mOpticalInsets.right, mOpticalInsets.top,
- mOpticalInsets.left, mOpticalInsets.bottom);
+ return Insets.of(opticalInsets.right, opticalInsets.top,
+ opticalInsets.left, opticalInsets.bottom);
} else {
- return mOpticalInsets;
+ return opticalInsets;
}
}
@@ -352,7 +332,7 @@
}
@Override
- public void setColorFilter(ColorFilter colorFilter) {
+ public void setColorFilter(@Nullable ColorFilter colorFilter) {
if (mPaint == null && colorFilter == null) {
// Fast common case -- leave at no color filter.
return;
@@ -362,14 +342,14 @@
}
@Override
- public void setTintList(ColorStateList tint) {
+ public void setTintList(@Nullable ColorStateList tint) {
mNinePatchState.mTint = tint;
mTintFilter = updateTintFilter(mTintFilter, tint, mNinePatchState.mTintMode);
invalidateSelf();
}
@Override
- public void setTintMode(PorterDuff.Mode tintMode) {
+ public void setTintMode(@Nullable PorterDuff.Mode tintMode) {
mNinePatchState.mTintMode = tintMode;
mTintFilter = updateTintFilter(mTintFilter, mNinePatchState.mTint, tintMode);
invalidateSelf();
@@ -409,10 +389,7 @@
@Override
public boolean isFilterBitmap() {
- if (mPaint == null) {
- return false;
- }
- return getPaint().isFilterBitmap();
+ return mPaint != null && getPaint().isFilterBitmap();
}
@Override
@@ -430,7 +407,7 @@
/**
* Updates the constant state from the values in the typed array.
*/
- private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
+ private void updateStateFromTypedArray(@NonNull TypedArray a) throws XmlPullParserException {
final Resources r = a.getResources();
final NinePatchState state = mNinePatchState;
@@ -491,12 +468,10 @@
if (tint != null) {
state.mTint = tint;
}
-
- state.mTargetDensity = Drawable.resolveDensity(r, state.mTargetDensity);
}
@Override
- public void applyTheme(Theme t) {
+ public void applyTheme(@NonNull Theme t) {
super.applyTheme(t);
final NinePatchState state = mNinePatchState;
@@ -528,6 +503,7 @@
return mNinePatchState != null && mNinePatchState.canApplyTheme();
}
+ @NonNull
public Paint getPaint() {
if (mPaint == null) {
mPaint = new Paint();
@@ -536,45 +512,26 @@
return mPaint;
}
- /**
- * Retrieves the width of the source .png file (before resizing).
- */
@Override
public int getIntrinsicWidth() {
return mBitmapWidth;
}
- /**
- * Retrieves the height of the source .png file (before resizing).
- */
@Override
public int getIntrinsicHeight() {
return mBitmapHeight;
}
@Override
- public int getMinimumWidth() {
- return mBitmapWidth;
- }
-
- @Override
- public int getMinimumHeight() {
- return mBitmapHeight;
- }
-
- /**
- * Returns a {@link android.graphics.PixelFormat graphics.PixelFormat}
- * value of OPAQUE or TRANSLUCENT.
- */
- @Override
public int getOpacity() {
- return mNinePatch.hasAlpha() || (mPaint != null && mPaint.getAlpha() < 255) ?
- PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
+ return mNinePatchState.mNinePatch.hasAlpha()
+ || (mPaint != null && mPaint.getAlpha() < 255) ?
+ PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
}
@Override
public Region getTransparentRegion() {
- return mNinePatch.getTransparentRegion(getBounds());
+ return mNinePatchState.mNinePatch.getTransparentRegion(getBounds());
}
@Override
@@ -587,7 +544,6 @@
public Drawable mutate() {
if (!mMutated && super.mutate() == this) {
mNinePatchState = new NinePatchState(mNinePatchState);
- mNinePatch = mNinePatchState.mNinePatch;
mMutated = true;
}
return this;
@@ -619,8 +575,9 @@
}
final static class NinePatchState extends ConstantState {
+ int mChangingConfigurations;
+
// Values loaded during inflation.
- int[] mThemeAttrs = null;
NinePatch mNinePatch = null;
ColorStateList mTint = null;
Mode mTintMode = DEFAULT_TINT_MODE;
@@ -628,10 +585,9 @@
Insets mOpticalInsets = Insets.NONE;
float mBaseAlpha = 1.0f;
boolean mDither = DEFAULT_DITHER;
- int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
boolean mAutoMirrored = false;
- int mChangingConfigurations;
+ int[] mThemeAttrs;
NinePatchState() {
// Empty constructor.
@@ -655,27 +611,24 @@
mAutoMirrored = autoMirror;
}
- // Copy constructor
-
- NinePatchState(@NonNull NinePatchState state) {
- // We don't deep-copy any fields because they are all immutable.
- mNinePatch = state.mNinePatch;
- mTint = state.mTint;
- mTintMode = state.mTintMode;
- mThemeAttrs = state.mThemeAttrs;
- mPadding = state.mPadding;
- mOpticalInsets = state.mOpticalInsets;
- mBaseAlpha = state.mBaseAlpha;
- mDither = state.mDither;
- mChangingConfigurations = state.mChangingConfigurations;
- mTargetDensity = state.mTargetDensity;
- mAutoMirrored = state.mAutoMirrored;
+ NinePatchState(@NonNull NinePatchState orig) {
+ mChangingConfigurations = orig.mChangingConfigurations;
+ mNinePatch = orig.mNinePatch;
+ mTint = orig.mTint;
+ mTintMode = orig.mTintMode;
+ mPadding = orig.mPadding;
+ mOpticalInsets = orig.mOpticalInsets;
+ mBaseAlpha = orig.mBaseAlpha;
+ mDither = orig.mDither;
+ mAutoMirrored = orig.mAutoMirrored;
+ mThemeAttrs = orig.mThemeAttrs;
}
@Override
public boolean canApplyTheme() {
return mThemeAttrs != null
- || (mTint != null && mTint.canApplyTheme());
+ || (mTint != null && mTint.canApplyTheme())
+ || super.canApplyTheme();
}
@Override
@@ -704,44 +657,98 @@
}
}
+ private void computeBitmapSize() {
+ final NinePatch ninePatch = mNinePatchState.mNinePatch;
+ if (ninePatch == null) {
+ return;
+ }
+
+ final int sourceDensity = ninePatch.getDensity();
+ final int targetDensity = mTargetDensity;
+
+ final Insets sourceOpticalInsets = mNinePatchState.mOpticalInsets;
+ if (sourceOpticalInsets != Insets.NONE) {
+ final int left = Drawable.scaleFromDensity(
+ sourceOpticalInsets.left, sourceDensity, targetDensity, true);
+ final int top = Drawable.scaleFromDensity(
+ sourceOpticalInsets.top, sourceDensity, targetDensity, true);
+ final int right = Drawable.scaleFromDensity(
+ sourceOpticalInsets.right, sourceDensity, targetDensity, true);
+ final int bottom = Drawable.scaleFromDensity(
+ sourceOpticalInsets.bottom, sourceDensity, targetDensity, true);
+ mOpticalInsets = Insets.of(left, top, right, bottom);
+ } else {
+ mOpticalInsets = Insets.NONE;
+ }
+
+ final Rect sourcePadding = mNinePatchState.mPadding;
+ if (sourcePadding != null) {
+ if (mPadding == null) {
+ mPadding = new Rect();
+ }
+ mPadding.left = Drawable.scaleFromDensity(
+ sourcePadding.left, sourceDensity, targetDensity, false);
+ mPadding.top = Drawable.scaleFromDensity(
+ sourcePadding.top, sourceDensity, targetDensity, false);
+ mPadding.right = Drawable.scaleFromDensity(
+ sourcePadding.right, sourceDensity, targetDensity, false);
+ mPadding.bottom = Drawable.scaleFromDensity(
+ sourcePadding.bottom, sourceDensity, targetDensity, false);
+ } else {
+ mPadding = null;
+ }
+
+ mBitmapHeight = Drawable.scaleFromDensity(
+ ninePatch.getHeight(), sourceDensity, targetDensity, true);
+ mBitmapWidth = Drawable.scaleFromDensity(
+ ninePatch.getWidth(), sourceDensity, targetDensity, true);
+
+ final NinePatch.InsetStruct insets = ninePatch.getBitmap().getNinePatchInsets();
+ if (insets != null) {
+ if (mOutlineInsets == null) {
+ mOutlineInsets = new Rect();
+ }
+ final Rect outlineInsets = insets.outlineRect;
+ mOutlineInsets.left = Drawable.scaleFromDensity(
+ outlineInsets.left, sourceDensity, targetDensity, false);
+ mOutlineInsets.top = Drawable.scaleFromDensity(
+ outlineInsets.top, sourceDensity, targetDensity, false);
+ mOutlineInsets.right = Drawable.scaleFromDensity(
+ outlineInsets.right, sourceDensity, targetDensity, false);
+ mOutlineInsets.bottom = Drawable.scaleFromDensity(
+ outlineInsets.bottom, sourceDensity, targetDensity, false);
+ mOutlineRadius = Drawable.scaleFromDensity(
+ insets.outlineRadius, sourceDensity, targetDensity);
+ } else {
+ mOutlineInsets = null;
+ }
+ }
+
/**
* The one constructor to rule them all. This is called by all public
* constructors to set the state and initialize local properties.
+ *
+ * @param state constant state to assign to the new drawable
*/
- private NinePatchDrawable(NinePatchState state, Resources res) {
+ private NinePatchDrawable(@NonNull NinePatchState state, @Nullable Resources res) {
mNinePatchState = state;
updateLocalState(res);
-
- // Push density applied by setNinePatchState into state.
- mNinePatchState.mTargetDensity = mTargetDensity;
}
/**
* Initializes local dynamic properties from state.
*/
- private void updateLocalState(Resources res) {
+ private void updateLocalState(@Nullable Resources res) {
final NinePatchState state = mNinePatchState;
- if (res != null) {
- final int densityDpi = res.getDisplayMetrics().densityDpi;
- mTargetDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
- } else {
- mTargetDensity = state.mTargetDensity;
- }
-
-
// If we can, avoid calling any methods that initialize Paint.
if (state.mDither != DEFAULT_DITHER) {
setDither(state.mDither);
}
- // Make a local copy of the padding.
- if (state.mPadding != null) {
- mPadding = new Rect(state.mPadding);
- }
-
+ mTargetDensity = Drawable.resolveDensity(res, mTargetDensity);
mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
- setNinePatch(state.mNinePatch);
+ computeBitmapSize();
}
}