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

Commit cba27925 authored by Chong Zhang's avatar Chong Zhang
Browse files

Prefer animation in ImageDecoder.decodeDrawable

Pass down a flag to prefer animation over still images
when decodeDrawble is used. Pass the flag via source
to avoid adding this flag to all create/createFrom/
nCreate method variants. Check the flag only in
native_create when we actually create the decoder.

bug: 120414514
bug: 78868457

Change-Id: I84b4edd0225df9eaa59df8a787bd5902146ab500
parent f165a18a
Loading
Loading
Loading
Loading
+26 −20
Original line number Diff line number Diff line
@@ -78,14 +78,18 @@ static jobject throw_exception(JNIEnv* env, ImageDecoder::Error error, const cha
    return nullptr;
}

static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream, jobject source) {
static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream,
        jobject source, jboolean preferAnimation) {
    if (!stream.get()) {
        return throw_exception(env, ImageDecoder::kSourceMalformedData, "Failed to create a stream",
                               nullptr, source);
    }
    std::unique_ptr<ImageDecoder> decoder(new ImageDecoder);
    SkCodec::Result result;
    auto codec = SkCodec::MakeFromStream(std::move(stream), &result, decoder->mPeeker.get());
    auto codec = SkCodec::MakeFromStream(
            std::move(stream), &result, decoder->mPeeker.get(),
            preferAnimation ? SkCodec::SelectionPolicy::kPreferAnimation
                            : SkCodec::SelectionPolicy::kPreferStillImage);
    if (jthrowable jexception = get_and_clear_exception(env)) {
        return throw_exception(env, ImageDecoder::kSourceException, "", jexception, source);
    }
@@ -124,7 +128,7 @@ static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream, jobj
}

static jobject ImageDecoder_nCreateFd(JNIEnv* env, jobject /*clazz*/,
        jobject fileDescriptor, jobject source) {
        jobject fileDescriptor, jboolean preferAnimation, jobject source) {
    int descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);

    struct stat fdStat;
@@ -142,11 +146,11 @@ static jobject ImageDecoder_nCreateFd(JNIEnv* env, jobject /*clazz*/,
    }

    std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file));
    return native_create(env, std::move(fileStream), source);
    return native_create(env, std::move(fileStream), source, preferAnimation);
}

static jobject ImageDecoder_nCreateInputStream(JNIEnv* env, jobject /*clazz*/,
        jobject is, jbyteArray storage, jobject source) {
        jobject is, jbyteArray storage, jboolean preferAnimation, jobject source) {
    std::unique_ptr<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage, false));

    if (!stream.get()) {
@@ -157,31 +161,33 @@ static jobject ImageDecoder_nCreateInputStream(JNIEnv* env, jobject /*clazz*/,
    std::unique_ptr<SkStream> bufferedStream(
        SkFrontBufferedStream::Make(std::move(stream),
        SkCodec::MinBufferedBytesNeeded()));
    return native_create(env, std::move(bufferedStream), source);
    return native_create(env, std::move(bufferedStream), source, preferAnimation);
}

static jobject ImageDecoder_nCreateAsset(JNIEnv* env, jobject /*clazz*/, jlong assetPtr,
                                         jobject source) {
static jobject ImageDecoder_nCreateAsset(JNIEnv* env, jobject /*clazz*/,
        jlong assetPtr, jboolean preferAnimation, jobject source) {
    Asset* asset = reinterpret_cast<Asset*>(assetPtr);
    std::unique_ptr<SkStream> stream(new AssetStreamAdaptor(asset));
    return native_create(env, std::move(stream), source);
    return native_create(env, std::move(stream), source, preferAnimation);
}

static jobject ImageDecoder_nCreateByteBuffer(JNIEnv* env, jobject /*clazz*/, jobject jbyteBuffer,
                                              jint initialPosition, jint limit, jobject source) {
static jobject ImageDecoder_nCreateByteBuffer(JNIEnv* env, jobject /*clazz*/,
        jobject jbyteBuffer, jint initialPosition, jint limit,
        jboolean preferAnimation, jobject source) {
    std::unique_ptr<SkStream> stream = CreateByteBufferStreamAdaptor(env, jbyteBuffer,
                                                                     initialPosition, limit);
    if (!stream) {
        return throw_exception(env, ImageDecoder::kSourceMalformedData, "Failed to read ByteBuffer",
                               nullptr, source);
    }
    return native_create(env, std::move(stream), source);
    return native_create(env, std::move(stream), source, preferAnimation);
}

static jobject ImageDecoder_nCreateByteArray(JNIEnv* env, jobject /*clazz*/, jbyteArray byteArray,
                                             jint offset, jint length, jobject source) {
static jobject ImageDecoder_nCreateByteArray(JNIEnv* env, jobject /*clazz*/,
        jbyteArray byteArray, jint offset, jint length,
        jboolean preferAnimation, jobject source) {
    std::unique_ptr<SkStream> stream(CreateByteArrayStreamAdaptor(env, byteArray, offset, length));
    return native_create(env, std::move(stream), source);
    return native_create(env, std::move(stream), source, preferAnimation);
}

jint postProcessAndRelease(JNIEnv* env, jobject jimageDecoder, std::unique_ptr<Canvas> canvas) {
@@ -514,11 +520,11 @@ static jobject ImageDecoder_nGetColorSpace(JNIEnv* env, jobject /*clazz*/, jlong
}

static const JNINativeMethod gImageDecoderMethods[] = {
    { "nCreate",        "(JLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;",    (void*) ImageDecoder_nCreateAsset },
    { "nCreate",        "(Ljava/nio/ByteBuffer;IILandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteBuffer },
    { "nCreate",        "([BIILandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteArray },
    { "nCreate",        "(Ljava/io/InputStream;[BLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateInputStream },
    { "nCreate",        "(Ljava/io/FileDescriptor;Landroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
    { "nCreate",        "(JZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;",    (void*) ImageDecoder_nCreateAsset },
    { "nCreate",        "(Ljava/nio/ByteBuffer;IIZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteBuffer },
    { "nCreate",        "([BIIZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteArray },
    { "nCreate",        "(Ljava/io/InputStream;[BZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateInputStream },
    { "nCreate",        "(Ljava/io/FileDescriptor;ZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
    { "nDecodeBitmap",  "(JLandroid/graphics/ImageDecoder;ZIILandroid/graphics/Rect;ZIZZZJZ)Landroid/graphics/Bitmap;",
                                                                 (void*) ImageDecoder_nDecodeBitmap },
    { "nGetSampledSize","(JI)Landroid/util/Size;",               (void*) ImageDecoder_nGetSampledSize },
+41 −39
Original line number Diff line number Diff line
@@ -214,7 +214,7 @@ public final class ImageDecoder implements AutoCloseable {

        /* @hide */
        @NonNull
        abstract ImageDecoder createImageDecoder() throws IOException;
        abstract ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException;
    };

    private static class ByteArraySource extends Source {
@@ -228,8 +228,8 @@ public final class ImageDecoder implements AutoCloseable {
        private final int    mLength;

        @Override
        public ImageDecoder createImageDecoder() throws IOException {
            return nCreate(mData, mOffset, mLength, this);
        public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException {
            return nCreate(mData, mOffset, mLength, preferAnimation, this);
        }
    }

@@ -240,14 +240,14 @@ public final class ImageDecoder implements AutoCloseable {
        private final ByteBuffer mBuffer;

        @Override
        public ImageDecoder createImageDecoder() throws IOException {
        public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException {
            if (!mBuffer.isDirect() && mBuffer.hasArray()) {
                int offset = mBuffer.arrayOffset() + mBuffer.position();
                int length = mBuffer.limit() - mBuffer.position();
                return nCreate(mBuffer.array(), offset, length, this);
                return nCreate(mBuffer.array(), offset, length, preferAnimation, this);
            }
            ByteBuffer buffer = mBuffer.slice();
            return nCreate(buffer, buffer.position(), buffer.limit(), this);
            return nCreate(buffer, buffer.position(), buffer.limit(), preferAnimation, this);
        }
    }

@@ -267,7 +267,7 @@ public final class ImageDecoder implements AutoCloseable {
        Resources getResources() { return mResources; }

        @Override
        public ImageDecoder createImageDecoder() throws IOException {
        public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException {
            AssetFileDescriptor assetFd = null;
            try {
                if (mUri.getScheme() == ContentResolver.SCHEME_CONTENT) {
@@ -284,26 +284,26 @@ public final class ImageDecoder implements AutoCloseable {
                    throw new FileNotFoundException(mUri.toString());
                }

                return createFromStream(is, true, this);
                return createFromStream(is, true, preferAnimation, this);
            }
            return createFromAssetFileDescriptor(assetFd, this);
            return createFromAssetFileDescriptor(assetFd, preferAnimation, this);
        }
    }

    @NonNull
    private static ImageDecoder createFromFile(@NonNull File file,
            @NonNull Source source) throws IOException {
            boolean preferAnimation, @NonNull Source source) throws IOException {
        FileInputStream stream = new FileInputStream(file);
        FileDescriptor fd = stream.getFD();
        try {
            Os.lseek(fd, 0, SEEK_CUR);
        } catch (ErrnoException e) {
            return createFromStream(stream, true, source);
            return createFromStream(stream, true, preferAnimation, source);
        }

        ImageDecoder decoder = null;
        try {
            decoder = nCreate(fd, source);
            decoder = nCreate(fd, preferAnimation, source);
        } finally {
            if (decoder == null) {
                IoUtils.closeQuietly(stream);
@@ -317,12 +317,12 @@ public final class ImageDecoder implements AutoCloseable {

    @NonNull
    private static ImageDecoder createFromStream(@NonNull InputStream is,
            boolean closeInputStream, Source source) throws IOException {
            boolean closeInputStream, boolean preferAnimation, Source source) throws IOException {
        // Arbitrary size matches BitmapFactory.
        byte[] storage = new byte[16 * 1024];
        ImageDecoder decoder = null;
        try {
            decoder = nCreate(is, storage, source);
            decoder = nCreate(is, storage, preferAnimation, source);
        } finally {
            if (decoder == null) {
                if (closeInputStream) {
@@ -340,7 +340,7 @@ public final class ImageDecoder implements AutoCloseable {

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

@@ -348,9 +348,9 @@ public final class ImageDecoder implements AutoCloseable {
        try {
            try {
                Os.lseek(fd, offset, SEEK_SET);
                decoder = nCreate(fd, source);
                decoder = nCreate(fd, preferAnimation, source);
            } catch (ErrnoException e) {
                decoder = createFromStream(new FileInputStream(fd), true, source);
                decoder = createFromStream(new FileInputStream(fd), true, preferAnimation, source);
            }
        } finally {
            if (decoder == null) {
@@ -388,7 +388,7 @@ public final class ImageDecoder implements AutoCloseable {
        public int getDensity() { return mInputDensity; }

        @Override
        public ImageDecoder createImageDecoder() throws IOException {
        public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException {

            synchronized (this) {
                if (mInputStream == null) {
@@ -396,7 +396,7 @@ public final class ImageDecoder implements AutoCloseable {
                }
                InputStream is = mInputStream;
                mInputStream = null;
                return createFromStream(is, false, this);
                return createFromStream(is, false, preferAnimation, this);
            }
        }
    }
@@ -434,14 +434,14 @@ public final class ImageDecoder implements AutoCloseable {
        }

        @Override
        public ImageDecoder createImageDecoder() throws IOException {
        public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException {
            synchronized (this) {
                if (mAssetInputStream == null) {
                    throw new IOException("Cannot reuse AssetInputStreamSource");
                }
                AssetInputStream ais = mAssetInputStream;
                mAssetInputStream = null;
                return createFromAsset(ais, this);
                return createFromAsset(ais, preferAnimation, this);
            }
        }
    }
@@ -469,7 +469,7 @@ public final class ImageDecoder implements AutoCloseable {
        }

        @Override
        public ImageDecoder createImageDecoder() throws IOException {
        public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException {
            TypedValue value = new TypedValue();
            // This is just used in order to access the underlying Asset and
            // keep it alive.
@@ -483,7 +483,7 @@ public final class ImageDecoder implements AutoCloseable {
                }
            }

            return createFromAsset((AssetInputStream) is, this);
            return createFromAsset((AssetInputStream) is, preferAnimation, this);
        }
    }

@@ -491,11 +491,11 @@ public final class ImageDecoder implements AutoCloseable {
     *  ImageDecoder will own the AssetInputStream.
     */
    private static ImageDecoder createFromAsset(AssetInputStream ais,
            Source source) throws IOException {
            boolean preferAnimation, Source source) throws IOException {
        ImageDecoder decoder = null;
        try {
            long asset = ais.getNativeAsset();
            decoder = nCreate(asset, source);
            decoder = nCreate(asset, preferAnimation, source);
        } finally {
            if (decoder == null) {
                IoUtils.closeQuietly(ais);
@@ -517,9 +517,9 @@ public final class ImageDecoder implements AutoCloseable {
        private final String mFileName;

        @Override
        public ImageDecoder createImageDecoder() throws IOException {
        public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException {
            InputStream is = mAssets.open(mFileName);
            return createFromAsset((AssetInputStream) is, this);
            return createFromAsset((AssetInputStream) is, preferAnimation, this);
        }
    }

@@ -531,8 +531,8 @@ public final class ImageDecoder implements AutoCloseable {
        private final File mFile;

        @Override
        public ImageDecoder createImageDecoder() throws IOException {
            return createFromFile(mFile, this);
        public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException {
            return createFromFile(mFile, preferAnimation, this);
        }
    }

@@ -544,7 +544,7 @@ public final class ImageDecoder implements AutoCloseable {
        private final Callable<AssetFileDescriptor> mCallable;

        @Override
        public ImageDecoder createImageDecoder() throws IOException {
        public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException {
            AssetFileDescriptor assetFd = null;
            try {
                assetFd = mCallable.call();
@@ -555,7 +555,7 @@ public final class ImageDecoder implements AutoCloseable {
                    throw new IOException(e);
                }
            }
            return createFromAssetFileDescriptor(assetFd, this);
            return createFromAssetFileDescriptor(assetFd, preferAnimation, this);
        }
    }

@@ -1740,7 +1740,7 @@ public final class ImageDecoder implements AutoCloseable {
    @NonNull
    private static Drawable decodeDrawableImpl(@NonNull Source src,
            @Nullable OnHeaderDecodedListener listener) throws IOException {
        try (ImageDecoder decoder = src.createImageDecoder()) {
        try (ImageDecoder decoder = src.createImageDecoder(true /*preferAnimation*/)) {
            decoder.mSource = src;
            decoder.callHeaderDecoded(listener, src);

@@ -1844,7 +1844,7 @@ public final class ImageDecoder implements AutoCloseable {
    @NonNull
    private static Bitmap decodeBitmapImpl(@NonNull Source src,
            @Nullable OnHeaderDecodedListener listener) throws IOException {
        try (ImageDecoder decoder = src.createImageDecoder()) {
        try (ImageDecoder decoder = src.createImageDecoder(false /*preferAnimation*/)) {
            decoder.mSource = src;
            decoder.callHeaderDecoded(listener, src);

@@ -1971,15 +1971,17 @@ public final class ImageDecoder implements AutoCloseable {
        }
    }

    private static native ImageDecoder nCreate(long asset, Source src) throws IOException;
    private static native ImageDecoder nCreate(ByteBuffer buffer, int position,
                                               int limit, Source src) throws IOException;
    private static native ImageDecoder nCreate(long asset,
            boolean preferAnimation, Source src) throws IOException;
    private static native ImageDecoder nCreate(ByteBuffer buffer, int position, int limit,
            boolean preferAnimation, Source src) throws IOException;
    private static native ImageDecoder nCreate(byte[] data, int offset, int length,
                                               Source src) throws IOException;
            boolean preferAnimation, Source src) throws IOException;
    private static native ImageDecoder nCreate(InputStream is, byte[] storage,
                                               Source src) throws IOException;
            boolean preferAnimation, Source src) throws IOException;
    // The fd must be seekable.
    private static native ImageDecoder nCreate(FileDescriptor fd, Source src) throws IOException;
    private static native ImageDecoder nCreate(FileDescriptor fd,
            boolean preferAnimation, Source src) throws IOException;
    @NonNull
    private static native Bitmap nDecodeBitmap(long nativePtr,
            @NonNull ImageDecoder decoder,