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

Commit 685c4aef authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Support custom creation of AFD for ImageDecoder.

ContentResolver.openTypedAssetFileDescriptor() has support for a
Bundle of options that can be used to communicate things like desired
thumbnail size, and also CancellationSignal to cancel large network
fetches when no longer needed.

Instead of adding all these to ImageDecoder, let developers provide
their own Callable<AssetFileDescriptor> so they can implement these
custom features.

Bug: 111268862
Test: atest cts/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
Change-Id: I51c509962f50dd08be94507169355b5da54d6782
parent cd084e45
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -13748,6 +13748,7 @@ package android.graphics {
    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.ImageDecoder.Source createSource(java.util.concurrent.Callable<android.content.res.AssetFileDescriptor>);
    method public static android.graphics.Bitmap decodeBitmap(android.graphics.ImageDecoder.Source, android.graphics.ImageDecoder.OnHeaderDecodedListener) throws java.io.IOException;
    method public static android.graphics.Bitmap decodeBitmap(android.graphics.ImageDecoder.Source) throws java.io.IOException;
    method public static android.graphics.drawable.Drawable decodeDrawable(android.graphics.ImageDecoder.Source, android.graphics.ImageDecoder.OnHeaderDecodedListener) throws java.io.IOException;
+70 −20
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Retention;
import java.nio.ByteBuffer;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicBoolean;

/**
@@ -283,26 +284,7 @@ public final class ImageDecoder implements AutoCloseable {

                return createFromStream(is, true, this);
            }

            final FileDescriptor fd = assetFd.getFileDescriptor();
            final long offset = assetFd.getStartOffset();

            ImageDecoder decoder = null;
            try {
                try {
                    Os.lseek(fd, offset, SEEK_SET);
                    decoder = nCreate(fd, this);
                } catch (ErrnoException e) {
                    decoder = createFromStream(new FileInputStream(fd), true, this);
                }
            } finally {
                if (decoder == null) {
                    IoUtils.closeQuietly(assetFd);
                } else {
                    decoder.mAssetFd = assetFd;
                }
            }
            return decoder;
            return createFromAssetFileDescriptor(assetFd, this);
        }
    }

@@ -354,6 +336,30 @@ public final class ImageDecoder implements AutoCloseable {
        return decoder;
    }

    @NonNull
    private static ImageDecoder createFromAssetFileDescriptor(@NonNull AssetFileDescriptor assetFd,
            Source source) throws IOException {
        final FileDescriptor fd = assetFd.getFileDescriptor();
        final long offset = assetFd.getStartOffset();

        ImageDecoder decoder = null;
        try {
            try {
                Os.lseek(fd, offset, SEEK_SET);
                decoder = nCreate(fd, source);
            } catch (ErrnoException e) {
                decoder = createFromStream(new FileInputStream(fd), true, source);
            }
        } finally {
            if (decoder == null) {
                IoUtils.closeQuietly(assetFd);
            } else {
                decoder.mAssetFd = assetFd;
            }
        }
        return decoder;
    }

    /**
     * For backwards compatibility, this does *not* close the InputStream.
     *
@@ -528,6 +534,29 @@ public final class ImageDecoder implements AutoCloseable {
        }
    }

    private static class CallableSource extends Source {
        CallableSource(@NonNull Callable<AssetFileDescriptor> callable) {
            mCallable = callable;
        }

        private final Callable<AssetFileDescriptor> mCallable;

        @Override
        public ImageDecoder createImageDecoder() throws IOException {
            AssetFileDescriptor assetFd = null;
            try {
                assetFd = mCallable.call();
            } catch (Exception e) {
                if (e instanceof IOException) {
                    throw (IOException) e;
                } else {
                    throw new IOException(e);
                }
            }
            return createFromAssetFileDescriptor(assetFd, this);
        }
    }

    /**
     *  Information about an encoded image.
     */
@@ -970,6 +999,27 @@ public final class ImageDecoder implements AutoCloseable {
        return new FileSource(file);
    }

    /**
     * Create a new {@link Source Source} from a {@link Callable} that returns a
     * new {@link AssetFileDescriptor} for each request. This provides control
     * over how the {@link AssetFileDescriptor} is created, such as passing
     * options into {@link ContentResolver#openTypedAssetFileDescriptor}, or
     * enabling use of a {@link android.os.CancellationSignal}.
     * <p>
     * It's important for the given {@link Callable} to return a new, unique
     * {@link AssetFileDescriptor} for each invocation, to support reuse of the
     * returned {@link Source Source}.
     *
     * @return a new Source object, which can be passed to
     *         {@link #decodeDrawable decodeDrawable} or {@link #decodeBitmap
     *         decodeBitmap}.
     */
    @AnyThread
    @NonNull
    public static Source createSource(@NonNull Callable<AssetFileDescriptor> callable) {
        return new CallableSource(callable);
    }

    /**
     *  Return the width and height of a given sample size.
     *