Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 40c59fde authored by Leon Scroggins III's avatar Leon Scroggins III
Browse files

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
parent 34b58512
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -27,9 +27,11 @@ import android.annotation.StyleRes;
import android.annotation.StyleableRes;
import android.content.pm.ActivityInfo;
import android.content.pm.ActivityInfo.Config;
import android.content.res.AssetManager.AssetInputStream;
import android.content.res.Configuration.NativeConfig;
import android.content.res.Resources.NotFoundException;
import android.graphics.Bitmap;
import android.graphics.ImageDecoder;
import android.graphics.Typeface;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
@@ -809,8 +811,13 @@ public class ResourcesImpl {
                } else {
                    final InputStream is = mAssets.openNonAsset(
                            value.assetCookie, file, AssetManager.ACCESS_STREAMING);
                    dr = Drawable.createFromResourceStream(wrapper, value, is, file, null);
                    is.close();
                    AssetInputStream ais = (AssetInputStream) is;
                    // ImageDecoder will close the input stream.
                    ImageDecoder.Source src = new ImageDecoder.AssetInputStreamSource(ais,
                            wrapper, value);
                    dr = ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
                        decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
                    });
                }
            } finally {
                stack.pop();
+59 −6
Original line number Diff line number Diff line
@@ -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) {