Add an asset source for ImageDecoder
Bug: 74545298
Test: I6a633553bbb5ff26d84aaf5371b8b43a770afd4f
This allows using ImageDecoder to decode a file in the "assets"
directory of an app.
Change-Id: I2193f052cc2e16c55c7f68f7e51e07cd24ee4df9
diff --git a/api/current.txt b/api/current.txt
index b69b2be..a62cc15 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -13608,6 +13608,7 @@
method public void close();
method public static android.graphics.ImageDecoder.Source createSource(android.content.res.Resources, int);
method public static android.graphics.ImageDecoder.Source createSource(android.content.ContentResolver, android.net.Uri);
+ method public static android.graphics.ImageDecoder.Source createSource(android.content.res.AssetManager, java.lang.String);
method public static android.graphics.ImageDecoder.Source createSource(java.nio.ByteBuffer);
method public static android.graphics.ImageDecoder.Source createSource(java.io.File);
method public static android.graphics.Bitmap decodeBitmap(android.graphics.ImageDecoder.Source, android.graphics.ImageDecoder.OnHeaderDecodedListener) throws java.io.IOException;
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 8196d66..5e81c37 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -26,6 +26,7 @@
import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.res.AssetFileDescriptor;
+import android.content.res.AssetManager;
import android.content.res.AssetManager.AssetInputStream;
import android.content.res.Resources;
import android.graphics.drawable.AnimatedImageDrawable;
@@ -294,25 +295,13 @@
@Override
public ImageDecoder createImageDecoder() throws IOException {
- ImageDecoder decoder = null;
synchronized (this) {
if (mAssetInputStream == null) {
throw new IOException("Cannot reuse AssetInputStreamSource");
}
AssetInputStream ais = mAssetInputStream;
mAssetInputStream = null;
- try {
- long asset = ais.getNativeAsset();
- decoder = nCreate(asset);
- } finally {
- if (decoder == null) {
- IoUtils.closeQuietly(ais);
- } else {
- decoder.mInputStream = ais;
- decoder.mOwnsInputStream = true;
- }
- }
- return decoder;
+ return createFromAsset(ais);
}
}
}
@@ -336,31 +325,53 @@
@Override
public ImageDecoder createImageDecoder() throws IOException {
- // This is just used in order to access the underlying Asset and
- // keep it alive. FIXME: Can we skip creating this object?
- InputStream is = null;
- ImageDecoder decoder = null;
TypedValue value = new TypedValue();
- try {
- is = mResources.openRawResource(mResId, value);
+ // This is just used in order to access the underlying Asset and
+ // keep it alive.
+ InputStream is = mResources.openRawResource(mResId, value);
- if (value.density == TypedValue.DENSITY_DEFAULT) {
- mResDensity = DisplayMetrics.DENSITY_DEFAULT;
- } else if (value.density != TypedValue.DENSITY_NONE) {
- mResDensity = value.density;
- }
-
- long asset = ((AssetInputStream) is).getNativeAsset();
- decoder = nCreate(asset);
- } finally {
- if (decoder == null) {
- IoUtils.closeQuietly(is);
- } else {
- decoder.mInputStream = is;
- decoder.mOwnsInputStream = true;
- }
+ if (value.density == TypedValue.DENSITY_DEFAULT) {
+ mResDensity = DisplayMetrics.DENSITY_DEFAULT;
+ } else if (value.density != TypedValue.DENSITY_NONE) {
+ mResDensity = value.density;
}
- return decoder;
+
+ return createFromAsset((AssetInputStream) is);
+ }
+ }
+
+ /**
+ * ImageDecoder will own the AssetInputStream.
+ */
+ private static ImageDecoder createFromAsset(AssetInputStream ais) throws IOException {
+ ImageDecoder decoder = null;
+ try {
+ long asset = ais.getNativeAsset();
+ decoder = nCreate(asset);
+ } finally {
+ if (decoder == null) {
+ IoUtils.closeQuietly(ais);
+ } else {
+ decoder.mInputStream = ais;
+ decoder.mOwnsInputStream = true;
+ }
+ }
+ return decoder;
+ }
+
+ private static class AssetSource extends Source {
+ AssetSource(@NonNull AssetManager assets, @NonNull String fileName) {
+ mAssets = assets;
+ mFileName = fileName;
+ }
+
+ private final AssetManager mAssets;
+ private final String mFileName;
+
+ @Override
+ public ImageDecoder createImageDecoder() throws IOException {
+ InputStream is = mAssets.open(mFileName);
+ return createFromAsset((AssetInputStream) is);
}
}
@@ -581,6 +592,14 @@
}
/**
+ * Create a new {@link Source} from a file in the "assets" directory.
+ */
+ @NonNull
+ public static Source createSource(@NonNull AssetManager assets, @NonNull String fileName) {
+ return new AssetSource(assets, fileName);
+ }
+
+ /**
* Create a new {@link Source} from a byte array.
*
* @param data byte array of compressed image data.