Call ImageDecoder directly in ResourcesImpl
Test: Existing tests Add a new (hidden) ImageDecoder.Source that accepts an AssetInputStream. This allows us to create an AnimatedImageDrawable without fear of the client closing the stream. Call it from ResourcesImpl instead of Drawable.createFromResourceStream. Change-Id: I07e00ca60c97538335a6310e830b73211fd8e7bb
This commit is contained in:
@@ -25,7 +25,7 @@ import android.annotation.Nullable;
|
||||
import android.annotation.RawRes;
|
||||
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;
|
||||
import android.graphics.drawable.Drawable;
|
||||
@@ -257,6 +257,63 @@ public final class ImageDecoder implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes ownership of the AssetInputStream.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static class AssetInputStreamSource extends Source {
|
||||
public AssetInputStreamSource(@NonNull AssetInputStream ais,
|
||||
@NonNull Resources res, @NonNull TypedValue value) {
|
||||
mAssetInputStream = ais;
|
||||
mResources = res;
|
||||
|
||||
if (value.density == TypedValue.DENSITY_DEFAULT) {
|
||||
mDensity = DisplayMetrics.DENSITY_DEFAULT;
|
||||
} else if (value.density != TypedValue.DENSITY_NONE) {
|
||||
mDensity = value.density;
|
||||
} else {
|
||||
mDensity = Bitmap.DENSITY_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
private AssetInputStream mAssetInputStream;
|
||||
private final Resources mResources;
|
||||
private final int mDensity;
|
||||
|
||||
@Override
|
||||
public Resources getResources() { return mResources; }
|
||||
|
||||
@Override
|
||||
public int getDensity() {
|
||||
return mDensity;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ResourceSource extends Source {
|
||||
ResourceSource(@NonNull Resources res, int resId) {
|
||||
mResources = res;
|
||||
@@ -290,11 +347,7 @@ public final class ImageDecoder implements AutoCloseable {
|
||||
mResDensity = value.density;
|
||||
}
|
||||
|
||||
if (!(is instanceof AssetManager.AssetInputStream)) {
|
||||
// This should never happen.
|
||||
throw new RuntimeException("Resource is not an asset?");
|
||||
}
|
||||
long asset = ((AssetManager.AssetInputStream) is).getNativeAsset();
|
||||
long asset = ((AssetInputStream) is).getNativeAsset();
|
||||
decoder = nCreate(asset);
|
||||
} finally {
|
||||
if (decoder == null) {
|
||||
|
||||
Reference in New Issue
Block a user