Loading core/java/android/view/PointerIcon.java +35 −2 Original line number Diff line number Diff line Loading @@ -23,6 +23,10 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.AnimationDrawable; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; Loading Loading @@ -396,6 +400,33 @@ public final class PointerIcon implements Parcelable { return true; } /** * Get the Bitmap from the Drawable. * * If the Bitmap needed to be scaled up to account for density, BitmapDrawable * handles this at draw time. But this class doesn't actually draw the Bitmap; * it is just a holder for native code to access its SkBitmap. So this needs to * get a version that is scaled to account for density. */ private Bitmap getBitmapFromDrawable(BitmapDrawable bitmapDrawable) { Bitmap bitmap = bitmapDrawable.getBitmap(); final int scaledWidth = bitmapDrawable.getIntrinsicWidth(); final int scaledHeight = bitmapDrawable.getIntrinsicHeight(); if (scaledWidth == bitmap.getWidth() && scaledHeight == bitmap.getHeight()) { return bitmap; } Rect src = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); RectF dst = new RectF(0, 0, scaledWidth, scaledHeight); Bitmap scaled = Bitmap.createBitmap(scaledWidth, scaledHeight, bitmap.getConfig()); Canvas canvas = new Canvas(scaled); Paint paint = new Paint(); paint.setFilterBitmap(true); canvas.drawBitmap(bitmap, src, dst, paint); return scaled; } private void loadResource(Context context, Resources resources, @XmlRes int resourceId) { final XmlResourceParser parser = resources.getXml(resourceId); final int bitmapRes; Loading Loading @@ -452,7 +483,8 @@ public final class PointerIcon implements Parcelable { + "is different. All frames should have the exact same size and " + "share the same hotspot."); } mBitmapFrames[i - 1] = ((BitmapDrawable)drawableFrame).getBitmap(); BitmapDrawable bitmapDrawableFrame = (BitmapDrawable) drawableFrame; mBitmapFrames[i - 1] = getBitmapFromDrawable(bitmapDrawableFrame); } } } Loading @@ -461,7 +493,8 @@ public final class PointerIcon implements Parcelable { + "refer to a bitmap drawable."); } final Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; final Bitmap bitmap = getBitmapFromDrawable(bitmapDrawable); validateHotSpot(bitmap, hotSpotX, hotSpotY); // Set the properties now that we have successfully loaded the icon. mBitmap = bitmap; Loading graphics/java/android/graphics/ImageDecoder.java +26 −2 Original line number Diff line number Diff line Loading @@ -438,6 +438,7 @@ public final class ImageDecoder implements AutoCloseable { private boolean mPreferRamOverQuality = false; private boolean mAsAlphaMask = false; private Rect mCropRect; private Rect mOutPaddingRect; private Source mSource; private PostProcessor mPostProcessor; Loading Loading @@ -764,6 +765,18 @@ public final class ImageDecoder implements AutoCloseable { mCropRect = subset; } /** * Set a Rect for retrieving nine patch padding. * * If the image is a nine patch, this Rect will be set to the padding * rectangle during decode. Otherwise it will not be modified. * * @hide */ public void setOutPaddingRect(@NonNull Rect outPadding) { mOutPaddingRect = outPadding; } /** * Specify whether the {@link Bitmap} should be mutable. * Loading Loading @@ -875,7 +888,6 @@ public final class ImageDecoder implements AutoCloseable { postProcessPtr, mDesiredWidth, mDesiredHeight, mCropRect, mMutable, mAllocator, mRequireUnpremultiplied, mPreferRamOverQuality, mAsAlphaMask); } private void callHeaderDecoded(@Nullable OnHeaderDecodedListener listener, Loading Loading @@ -948,7 +960,10 @@ public final class ImageDecoder implements AutoCloseable { if (np != null && NinePatch.isNinePatchChunk(np)) { Rect opticalInsets = new Rect(); bm.getOpticalInsets(opticalInsets); Rect padding = new Rect(); Rect padding = decoder.mOutPaddingRect; if (padding == null) { padding = new Rect(); } nGetPadding(decoder.mNativePtr, padding); return new NinePatchDrawable(res, bm, np, padding, opticalInsets, null); Loading Loading @@ -991,6 +1006,15 @@ public final class ImageDecoder implements AutoCloseable { final int srcDensity = computeDensity(src, decoder); Bitmap bm = decoder.decodeBitmap(); bm.setDensity(srcDensity); Rect padding = decoder.mOutPaddingRect; if (padding != null) { byte[] np = bm.getNinePatchChunk(); if (np != null && NinePatch.isNinePatchChunk(np)) { nGetPadding(decoder.mNativePtr, padding); } } return bm; } } Loading graphics/java/android/graphics/drawable/BitmapDrawable.java +59 −26 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import android.graphics.BitmapFactory; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.ImageDecoder; import android.graphics.Insets; import android.graphics.Matrix; import android.graphics.Outline; Loading @@ -49,6 +50,7 @@ import com.android.internal.R; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; Loading Loading @@ -111,7 +113,7 @@ public class BitmapDrawable extends Drawable { */ @Deprecated public BitmapDrawable() { mBitmapState = new BitmapState((Bitmap) null); init(new BitmapState((Bitmap) null), null); } /** Loading @@ -124,8 +126,7 @@ public class BitmapDrawable extends Drawable { @SuppressWarnings("unused") @Deprecated public BitmapDrawable(Resources res) { mBitmapState = new BitmapState((Bitmap) null); mBitmapState.mTargetDensity = mTargetDensity; init(new BitmapState((Bitmap) null), res); } /** Loading @@ -135,7 +136,7 @@ public class BitmapDrawable extends Drawable { */ @Deprecated public BitmapDrawable(Bitmap bitmap) { this(new BitmapState(bitmap), null); init(new BitmapState(bitmap), null); } /** Loading @@ -143,8 +144,7 @@ public class BitmapDrawable extends Drawable { * the display metrics of the resources. */ public BitmapDrawable(Resources res, Bitmap bitmap) { this(new BitmapState(bitmap), res); mBitmapState.mTargetDensity = mTargetDensity; init(new BitmapState(bitmap), res); } /** Loading @@ -154,10 +154,7 @@ public class BitmapDrawable extends Drawable { */ @Deprecated public BitmapDrawable(String filepath) { this(new BitmapState(BitmapFactory.decodeFile(filepath)), null); if (mBitmapState.mBitmap == null) { android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath); } this(null, filepath); } /** Loading @@ -165,12 +162,23 @@ public class BitmapDrawable extends Drawable { */ @SuppressWarnings({ "unused", "ChainingConstructorIgnoresParameter" }) public BitmapDrawable(Resources res, String filepath) { this(new BitmapState(BitmapFactory.decodeFile(filepath)), null); mBitmapState.mTargetDensity = mTargetDensity; Bitmap bitmap = null; try (FileInputStream stream = new FileInputStream(filepath)) { bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(res, stream), (decoder, info, src) -> { decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE); }); } catch (Exception e) { /* do nothing. This matches the behavior of BitmapFactory.decodeFile() If the exception happened on decode, mBitmapState.mBitmap will be null. */ } finally { init(new BitmapState(bitmap), res); if (mBitmapState.mBitmap == null) { android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath); } } } /** * Create a drawable by decoding a bitmap from the given input stream. Loading @@ -179,10 +187,7 @@ public class BitmapDrawable extends Drawable { */ @Deprecated public BitmapDrawable(java.io.InputStream is) { this(new BitmapState(BitmapFactory.decodeStream(is)), null); if (mBitmapState.mBitmap == null) { android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is); } this(null, is); } /** Loading @@ -190,12 +195,23 @@ public class BitmapDrawable extends Drawable { */ @SuppressWarnings({ "unused", "ChainingConstructorIgnoresParameter" }) public BitmapDrawable(Resources res, java.io.InputStream is) { this(new BitmapState(BitmapFactory.decodeStream(is)), null); mBitmapState.mTargetDensity = mTargetDensity; Bitmap bitmap = null; try { bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(res, is), (decoder, info, src) -> { decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE); }); } catch (Exception e) { /* do nothing. This matches the behavior of BitmapFactory.decodeStream() If the exception happened on decode, mBitmapState.mBitmap will be null. */ } finally { init(new BitmapState(bitmap), res); if (mBitmapState.mBitmap == null) { android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is); } } } /** * Returns the paint used to render this drawable. Loading Loading @@ -812,9 +828,19 @@ public class BitmapDrawable extends Drawable { } } int density = Bitmap.DENSITY_NONE; if (value.density == TypedValue.DENSITY_DEFAULT) { density = DisplayMetrics.DENSITY_DEFAULT; } else if (value.density != TypedValue.DENSITY_NONE) { density = value.density; } Bitmap bitmap = null; try (InputStream is = r.openRawResource(srcResId, value)) { bitmap = BitmapFactory.decodeResourceStream(r, value, is, null, null); ImageDecoder.Source source = ImageDecoder.createSource(r, is, density); bitmap = ImageDecoder.decodeBitmap(source, (decoder, info, src) -> { decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE); }); } catch (Exception e) { // Do nothing and pick up the error below. } Loading Loading @@ -1013,14 +1039,21 @@ public class BitmapDrawable extends Drawable { } } private BitmapDrawable(BitmapState state, Resources res) { init(state, res); } /** * The one constructor to rule them all. This is called by all public * The one helper to rule them all. This is called by all public & private * constructors to set the state and initialize local properties. */ private BitmapDrawable(BitmapState state, Resources res) { private void init(BitmapState state, Resources res) { mBitmapState = state; updateLocalState(res); if (mBitmapState != null && res != null) { mBitmapState.mTargetDensity = mTargetDensity; } } /** Loading graphics/java/android/graphics/drawable/Drawable.java +38 −5 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.ImageDecoder; import android.graphics.Insets; import android.graphics.NinePatch; import android.graphics.Outline; Loading @@ -50,11 +51,13 @@ import android.graphics.Xfermode; import android.os.Trace; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.util.StateSet; import android.util.TypedValue; import android.util.Xml; import android.view.View; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; Loading Loading @@ -1175,6 +1178,10 @@ public abstract class Drawable { return null; } if (opts == null) { return getBitmapDrawable(res, value, is); } /* ugh. The decodeStream contract is that we have already allocated the pad rect, but if the bitmap does not had a ninepatch chunk, then the pad will be ignored. If we could change this to lazily Loading Loading @@ -1207,6 +1214,33 @@ public abstract class Drawable { return null; } private static Drawable getBitmapDrawable(Resources res, TypedValue value, InputStream is) { try { ImageDecoder.Source source = null; if (value != null) { int density = Bitmap.DENSITY_NONE; if (value.density == TypedValue.DENSITY_DEFAULT) { density = DisplayMetrics.DENSITY_DEFAULT; } else if (value.density != TypedValue.DENSITY_NONE) { density = value.density; } source = ImageDecoder.createSource(res, is, density); } else { source = ImageDecoder.createSource(res, is); } return ImageDecoder.decodeDrawable(source, (decoder, info, src) -> { decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE); }); } catch (IOException e) { /* do nothing. If the exception happened on decode, the drawable will be null. */ Log.e("Drawable", "Unable to decode stream: " + e); } return null; } /** * Create a drawable from an XML document. For more information on how to * create resources in XML, see Loading Loading @@ -1306,11 +1340,10 @@ public abstract class Drawable { } Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, pathName); try { Bitmap bm = BitmapFactory.decodeFile(pathName); if (bm != null) { return drawableFromBitmap(null, bm, null, null, null, pathName); } try (FileInputStream stream = new FileInputStream(pathName)) { return getBitmapDrawable(null, null, stream); } catch(IOException e) { // Do nothing; we will just return null if the FileInputStream had an error } finally { Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); } Loading graphics/java/android/graphics/drawable/NinePatchDrawable.java +14 −7 Original line number Diff line number Diff line Loading @@ -24,9 +24,9 @@ import android.content.res.Resources; import android.content.res.Resources.Theme; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.ImageDecoder; import android.graphics.Insets; import android.graphics.NinePatch; import android.graphics.Outline; Loading Loading @@ -211,7 +211,8 @@ public class NinePatchDrawable extends Drawable { restoreAlpha = -1; } final boolean needsDensityScaling = canvas.getDensity() == 0; final boolean needsDensityScaling = canvas.getDensity() == 0 && Bitmap.DENSITY_NONE != state.mNinePatch.getDensity(); if (needsDensityScaling) { restoreToCount = restoreToCount >= 0 ? restoreToCount : canvas.save(); Loading Loading @@ -421,10 +422,6 @@ public class NinePatchDrawable extends Drawable { final int srcResId = a.getResourceId(R.styleable.NinePatchDrawable_src, 0); if (srcResId != 0) { final BitmapFactory.Options options = new BitmapFactory.Options(); options.inDither = !state.mDither; options.inScreenDensity = r.getDisplayMetrics().noncompatDensityDpi; final Rect padding = new Rect(); final Rect opticalInsets = new Rect(); Bitmap bitmap = null; Loading @@ -433,7 +430,17 @@ public class NinePatchDrawable extends Drawable { final TypedValue value = new TypedValue(); final InputStream is = r.openRawResource(srcResId, value); bitmap = BitmapFactory.decodeResourceStream(r, value, is, padding, options); int density = Bitmap.DENSITY_NONE; if (value.density == TypedValue.DENSITY_DEFAULT) { density = DisplayMetrics.DENSITY_DEFAULT; } else if (value.density != TypedValue.DENSITY_NONE) { density = value.density; } ImageDecoder.Source source = ImageDecoder.createSource(r, is, density); bitmap = ImageDecoder.decodeBitmap(source, (decoder, info, src) -> { decoder.setOutPaddingRect(padding); decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE); }); is.close(); } catch (IOException e) { Loading Loading
core/java/android/view/PointerIcon.java +35 −2 Original line number Diff line number Diff line Loading @@ -23,6 +23,10 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.AnimationDrawable; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; Loading Loading @@ -396,6 +400,33 @@ public final class PointerIcon implements Parcelable { return true; } /** * Get the Bitmap from the Drawable. * * If the Bitmap needed to be scaled up to account for density, BitmapDrawable * handles this at draw time. But this class doesn't actually draw the Bitmap; * it is just a holder for native code to access its SkBitmap. So this needs to * get a version that is scaled to account for density. */ private Bitmap getBitmapFromDrawable(BitmapDrawable bitmapDrawable) { Bitmap bitmap = bitmapDrawable.getBitmap(); final int scaledWidth = bitmapDrawable.getIntrinsicWidth(); final int scaledHeight = bitmapDrawable.getIntrinsicHeight(); if (scaledWidth == bitmap.getWidth() && scaledHeight == bitmap.getHeight()) { return bitmap; } Rect src = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); RectF dst = new RectF(0, 0, scaledWidth, scaledHeight); Bitmap scaled = Bitmap.createBitmap(scaledWidth, scaledHeight, bitmap.getConfig()); Canvas canvas = new Canvas(scaled); Paint paint = new Paint(); paint.setFilterBitmap(true); canvas.drawBitmap(bitmap, src, dst, paint); return scaled; } private void loadResource(Context context, Resources resources, @XmlRes int resourceId) { final XmlResourceParser parser = resources.getXml(resourceId); final int bitmapRes; Loading Loading @@ -452,7 +483,8 @@ public final class PointerIcon implements Parcelable { + "is different. All frames should have the exact same size and " + "share the same hotspot."); } mBitmapFrames[i - 1] = ((BitmapDrawable)drawableFrame).getBitmap(); BitmapDrawable bitmapDrawableFrame = (BitmapDrawable) drawableFrame; mBitmapFrames[i - 1] = getBitmapFromDrawable(bitmapDrawableFrame); } } } Loading @@ -461,7 +493,8 @@ public final class PointerIcon implements Parcelable { + "refer to a bitmap drawable."); } final Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; final Bitmap bitmap = getBitmapFromDrawable(bitmapDrawable); validateHotSpot(bitmap, hotSpotX, hotSpotY); // Set the properties now that we have successfully loaded the icon. mBitmap = bitmap; Loading
graphics/java/android/graphics/ImageDecoder.java +26 −2 Original line number Diff line number Diff line Loading @@ -438,6 +438,7 @@ public final class ImageDecoder implements AutoCloseable { private boolean mPreferRamOverQuality = false; private boolean mAsAlphaMask = false; private Rect mCropRect; private Rect mOutPaddingRect; private Source mSource; private PostProcessor mPostProcessor; Loading Loading @@ -764,6 +765,18 @@ public final class ImageDecoder implements AutoCloseable { mCropRect = subset; } /** * Set a Rect for retrieving nine patch padding. * * If the image is a nine patch, this Rect will be set to the padding * rectangle during decode. Otherwise it will not be modified. * * @hide */ public void setOutPaddingRect(@NonNull Rect outPadding) { mOutPaddingRect = outPadding; } /** * Specify whether the {@link Bitmap} should be mutable. * Loading Loading @@ -875,7 +888,6 @@ public final class ImageDecoder implements AutoCloseable { postProcessPtr, mDesiredWidth, mDesiredHeight, mCropRect, mMutable, mAllocator, mRequireUnpremultiplied, mPreferRamOverQuality, mAsAlphaMask); } private void callHeaderDecoded(@Nullable OnHeaderDecodedListener listener, Loading Loading @@ -948,7 +960,10 @@ public final class ImageDecoder implements AutoCloseable { if (np != null && NinePatch.isNinePatchChunk(np)) { Rect opticalInsets = new Rect(); bm.getOpticalInsets(opticalInsets); Rect padding = new Rect(); Rect padding = decoder.mOutPaddingRect; if (padding == null) { padding = new Rect(); } nGetPadding(decoder.mNativePtr, padding); return new NinePatchDrawable(res, bm, np, padding, opticalInsets, null); Loading Loading @@ -991,6 +1006,15 @@ public final class ImageDecoder implements AutoCloseable { final int srcDensity = computeDensity(src, decoder); Bitmap bm = decoder.decodeBitmap(); bm.setDensity(srcDensity); Rect padding = decoder.mOutPaddingRect; if (padding != null) { byte[] np = bm.getNinePatchChunk(); if (np != null && NinePatch.isNinePatchChunk(np)) { nGetPadding(decoder.mNativePtr, padding); } } return bm; } } Loading
graphics/java/android/graphics/drawable/BitmapDrawable.java +59 −26 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import android.graphics.BitmapFactory; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.ImageDecoder; import android.graphics.Insets; import android.graphics.Matrix; import android.graphics.Outline; Loading @@ -49,6 +50,7 @@ import com.android.internal.R; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; Loading Loading @@ -111,7 +113,7 @@ public class BitmapDrawable extends Drawable { */ @Deprecated public BitmapDrawable() { mBitmapState = new BitmapState((Bitmap) null); init(new BitmapState((Bitmap) null), null); } /** Loading @@ -124,8 +126,7 @@ public class BitmapDrawable extends Drawable { @SuppressWarnings("unused") @Deprecated public BitmapDrawable(Resources res) { mBitmapState = new BitmapState((Bitmap) null); mBitmapState.mTargetDensity = mTargetDensity; init(new BitmapState((Bitmap) null), res); } /** Loading @@ -135,7 +136,7 @@ public class BitmapDrawable extends Drawable { */ @Deprecated public BitmapDrawable(Bitmap bitmap) { this(new BitmapState(bitmap), null); init(new BitmapState(bitmap), null); } /** Loading @@ -143,8 +144,7 @@ public class BitmapDrawable extends Drawable { * the display metrics of the resources. */ public BitmapDrawable(Resources res, Bitmap bitmap) { this(new BitmapState(bitmap), res); mBitmapState.mTargetDensity = mTargetDensity; init(new BitmapState(bitmap), res); } /** Loading @@ -154,10 +154,7 @@ public class BitmapDrawable extends Drawable { */ @Deprecated public BitmapDrawable(String filepath) { this(new BitmapState(BitmapFactory.decodeFile(filepath)), null); if (mBitmapState.mBitmap == null) { android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath); } this(null, filepath); } /** Loading @@ -165,12 +162,23 @@ public class BitmapDrawable extends Drawable { */ @SuppressWarnings({ "unused", "ChainingConstructorIgnoresParameter" }) public BitmapDrawable(Resources res, String filepath) { this(new BitmapState(BitmapFactory.decodeFile(filepath)), null); mBitmapState.mTargetDensity = mTargetDensity; Bitmap bitmap = null; try (FileInputStream stream = new FileInputStream(filepath)) { bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(res, stream), (decoder, info, src) -> { decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE); }); } catch (Exception e) { /* do nothing. This matches the behavior of BitmapFactory.decodeFile() If the exception happened on decode, mBitmapState.mBitmap will be null. */ } finally { init(new BitmapState(bitmap), res); if (mBitmapState.mBitmap == null) { android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath); } } } /** * Create a drawable by decoding a bitmap from the given input stream. Loading @@ -179,10 +187,7 @@ public class BitmapDrawable extends Drawable { */ @Deprecated public BitmapDrawable(java.io.InputStream is) { this(new BitmapState(BitmapFactory.decodeStream(is)), null); if (mBitmapState.mBitmap == null) { android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is); } this(null, is); } /** Loading @@ -190,12 +195,23 @@ public class BitmapDrawable extends Drawable { */ @SuppressWarnings({ "unused", "ChainingConstructorIgnoresParameter" }) public BitmapDrawable(Resources res, java.io.InputStream is) { this(new BitmapState(BitmapFactory.decodeStream(is)), null); mBitmapState.mTargetDensity = mTargetDensity; Bitmap bitmap = null; try { bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(res, is), (decoder, info, src) -> { decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE); }); } catch (Exception e) { /* do nothing. This matches the behavior of BitmapFactory.decodeStream() If the exception happened on decode, mBitmapState.mBitmap will be null. */ } finally { init(new BitmapState(bitmap), res); if (mBitmapState.mBitmap == null) { android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is); } } } /** * Returns the paint used to render this drawable. Loading Loading @@ -812,9 +828,19 @@ public class BitmapDrawable extends Drawable { } } int density = Bitmap.DENSITY_NONE; if (value.density == TypedValue.DENSITY_DEFAULT) { density = DisplayMetrics.DENSITY_DEFAULT; } else if (value.density != TypedValue.DENSITY_NONE) { density = value.density; } Bitmap bitmap = null; try (InputStream is = r.openRawResource(srcResId, value)) { bitmap = BitmapFactory.decodeResourceStream(r, value, is, null, null); ImageDecoder.Source source = ImageDecoder.createSource(r, is, density); bitmap = ImageDecoder.decodeBitmap(source, (decoder, info, src) -> { decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE); }); } catch (Exception e) { // Do nothing and pick up the error below. } Loading Loading @@ -1013,14 +1039,21 @@ public class BitmapDrawable extends Drawable { } } private BitmapDrawable(BitmapState state, Resources res) { init(state, res); } /** * The one constructor to rule them all. This is called by all public * The one helper to rule them all. This is called by all public & private * constructors to set the state and initialize local properties. */ private BitmapDrawable(BitmapState state, Resources res) { private void init(BitmapState state, Resources res) { mBitmapState = state; updateLocalState(res); if (mBitmapState != null && res != null) { mBitmapState.mTargetDensity = mTargetDensity; } } /** Loading
graphics/java/android/graphics/drawable/Drawable.java +38 −5 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.ImageDecoder; import android.graphics.Insets; import android.graphics.NinePatch; import android.graphics.Outline; Loading @@ -50,11 +51,13 @@ import android.graphics.Xfermode; import android.os.Trace; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.util.StateSet; import android.util.TypedValue; import android.util.Xml; import android.view.View; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; Loading Loading @@ -1175,6 +1178,10 @@ public abstract class Drawable { return null; } if (opts == null) { return getBitmapDrawable(res, value, is); } /* ugh. The decodeStream contract is that we have already allocated the pad rect, but if the bitmap does not had a ninepatch chunk, then the pad will be ignored. If we could change this to lazily Loading Loading @@ -1207,6 +1214,33 @@ public abstract class Drawable { return null; } private static Drawable getBitmapDrawable(Resources res, TypedValue value, InputStream is) { try { ImageDecoder.Source source = null; if (value != null) { int density = Bitmap.DENSITY_NONE; if (value.density == TypedValue.DENSITY_DEFAULT) { density = DisplayMetrics.DENSITY_DEFAULT; } else if (value.density != TypedValue.DENSITY_NONE) { density = value.density; } source = ImageDecoder.createSource(res, is, density); } else { source = ImageDecoder.createSource(res, is); } return ImageDecoder.decodeDrawable(source, (decoder, info, src) -> { decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE); }); } catch (IOException e) { /* do nothing. If the exception happened on decode, the drawable will be null. */ Log.e("Drawable", "Unable to decode stream: " + e); } return null; } /** * Create a drawable from an XML document. For more information on how to * create resources in XML, see Loading Loading @@ -1306,11 +1340,10 @@ public abstract class Drawable { } Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, pathName); try { Bitmap bm = BitmapFactory.decodeFile(pathName); if (bm != null) { return drawableFromBitmap(null, bm, null, null, null, pathName); } try (FileInputStream stream = new FileInputStream(pathName)) { return getBitmapDrawable(null, null, stream); } catch(IOException e) { // Do nothing; we will just return null if the FileInputStream had an error } finally { Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); } Loading
graphics/java/android/graphics/drawable/NinePatchDrawable.java +14 −7 Original line number Diff line number Diff line Loading @@ -24,9 +24,9 @@ import android.content.res.Resources; import android.content.res.Resources.Theme; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.ImageDecoder; import android.graphics.Insets; import android.graphics.NinePatch; import android.graphics.Outline; Loading Loading @@ -211,7 +211,8 @@ public class NinePatchDrawable extends Drawable { restoreAlpha = -1; } final boolean needsDensityScaling = canvas.getDensity() == 0; final boolean needsDensityScaling = canvas.getDensity() == 0 && Bitmap.DENSITY_NONE != state.mNinePatch.getDensity(); if (needsDensityScaling) { restoreToCount = restoreToCount >= 0 ? restoreToCount : canvas.save(); Loading Loading @@ -421,10 +422,6 @@ public class NinePatchDrawable extends Drawable { final int srcResId = a.getResourceId(R.styleable.NinePatchDrawable_src, 0); if (srcResId != 0) { final BitmapFactory.Options options = new BitmapFactory.Options(); options.inDither = !state.mDither; options.inScreenDensity = r.getDisplayMetrics().noncompatDensityDpi; final Rect padding = new Rect(); final Rect opticalInsets = new Rect(); Bitmap bitmap = null; Loading @@ -433,7 +430,17 @@ public class NinePatchDrawable extends Drawable { final TypedValue value = new TypedValue(); final InputStream is = r.openRawResource(srcResId, value); bitmap = BitmapFactory.decodeResourceStream(r, value, is, padding, options); int density = Bitmap.DENSITY_NONE; if (value.density == TypedValue.DENSITY_DEFAULT) { density = DisplayMetrics.DENSITY_DEFAULT; } else if (value.density != TypedValue.DENSITY_NONE) { density = value.density; } ImageDecoder.Source source = ImageDecoder.createSource(r, is, density); bitmap = ImageDecoder.decodeBitmap(source, (decoder, info, src) -> { decoder.setOutPaddingRect(padding); decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE); }); is.close(); } catch (IOException e) { Loading