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

Commit 84d069d1 authored by Leon Scroggins III's avatar Leon Scroggins III Committed by John Reck
Browse files

Fix AnimatedImageDrawables using ByteBuffers

Bug: 140715166
Test: I56dc6e9865c2701746c95ea584bcc70fe4d62a6c

AnimatedImageDrawable, when created from a ByteBuffer, needs to get a
pointer to the JNI interface in order to read the ByteBuffer (or
byte[]). But the AnimatedImageThread is not attached to the JVM. Attach
it as necessary.

Change-Id: I51b69b5b70f8c5865d5e5ed065e42267fa556202
Merged-In: I51b69b5b70f8c5865d5e5ed065e42267fa556202
(cherry picked from commit a7ec12f7)
parent 678feaf4
Loading
Loading
Loading
Loading
+24 −5
Original line number Original line Diff line number Diff line
#include "ByteBufferStreamAdaptor.h"
#include "ByteBufferStreamAdaptor.h"
#include "core_jni_helpers.h"
#include "core_jni_helpers.h"
#include "Utils.h"
#include "Utils.h"
#include <jni.h>


#include <SkStream.h>
#include <SkStream.h>


@@ -9,6 +10,24 @@ using namespace android;
static jmethodID gByteBuffer_getMethodID;
static jmethodID gByteBuffer_getMethodID;
static jmethodID gByteBuffer_setPositionMethodID;
static jmethodID gByteBuffer_setPositionMethodID;


/**
 * Helper method for accessing the JNI interface pointer.
 *
 * Image decoding (which this supports) is started on a thread that is already
 * attached to the Java VM. But an AnimatedImageDrawable continues decoding on
 * the AnimatedImageThread, which is not attached. This will attach if
 * necessary.
 */
static JNIEnv* requireEnv(JavaVM* jvm) {
    JNIEnv* env;
    if (jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
        if (jvm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) {
            LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!");
        }
    }
    return env;
}

class ByteBufferStream : public SkStreamAsset {
class ByteBufferStream : public SkStreamAsset {
private:
private:
    ByteBufferStream(JavaVM* jvm, jobject jbyteBuffer, size_t initialPosition, size_t length,
    ByteBufferStream(JavaVM* jvm, jobject jbyteBuffer, size_t initialPosition, size_t length,
@@ -46,7 +65,7 @@ public:
    }
    }


    ~ByteBufferStream() override {
    ~ByteBufferStream() override {
        auto* env = get_env_or_die(mJvm);
        auto* env = requireEnv(mJvm);
        env->DeleteGlobalRef(mByteBuffer);
        env->DeleteGlobalRef(mByteBuffer);
        env->DeleteGlobalRef(mStorage);
        env->DeleteGlobalRef(mStorage);
    }
    }
@@ -63,7 +82,7 @@ public:
            return this->setPosition(mPosition + size) ? size : 0;
            return this->setPosition(mPosition + size) ? size : 0;
        }
        }


        auto* env = get_env_or_die(mJvm);
        auto* env = requireEnv(mJvm);
        size_t bytesRead = 0;
        size_t bytesRead = 0;
        do {
        do {
            const size_t requested = (size > kStorageSize) ? kStorageSize : size;
            const size_t requested = (size > kStorageSize) ? kStorageSize : size;
@@ -146,7 +165,7 @@ private:


    // Range has already been checked by the caller.
    // Range has already been checked by the caller.
    bool setPosition(size_t newPosition) {
    bool setPosition(size_t newPosition) {
        auto* env = get_env_or_die(mJvm);
        auto* env = requireEnv(mJvm);
        env->CallObjectMethod(mByteBuffer, gByteBuffer_setPositionMethodID,
        env->CallObjectMethod(mByteBuffer, gByteBuffer_setPositionMethodID,
                              newPosition + mInitialPosition);
                              newPosition + mInitialPosition);
        if (env->ExceptionCheck()) {
        if (env->ExceptionCheck()) {
@@ -185,7 +204,7 @@ public:
    }
    }


    ~ByteArrayStream() override {
    ~ByteArrayStream() override {
        auto* env = get_env_or_die(mJvm);
        auto* env = requireEnv(mJvm);
        env->DeleteGlobalRef(mByteArray);
        env->DeleteGlobalRef(mByteArray);
    }
    }


@@ -197,7 +216,7 @@ public:
            return 0;
            return 0;
        }
        }


        auto* env = get_env_or_die(mJvm);
        auto* env = requireEnv(mJvm);
        if (buffer) {
        if (buffer) {
            env->GetByteArrayRegion(mByteArray, mPosition + mOffset, size,
            env->GetByteArrayRegion(mByteArray, mPosition + mOffset, size,
                                    reinterpret_cast<jbyte*>(buffer));
                                    reinterpret_cast<jbyte*>(buffer));