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

Commit 127d31a6 authored by Leon Scroggins III's avatar Leon Scroggins III
Browse files

Expose AnimatedImageDrawable

Bug: 63908092
Test: I85979ae3d8c6a6dae6e4299dc3be291e12024290

Implement Animatable2, adding listeners for starting and ending the
animation.

Add setLoopCount for changing the loop count.

Add the ability to inflate from XML, by using the name of the class or
"animated-image", which mimics "nine-patch", "bitmap" etc.

Move internal variables to a State class so that they can be transferred
to a default constructed AnimatedImageDrawable.

Change-Id: Ice8149e7de55f7ffb4b4ba9dd9c856582fc42bc9
parent 057c91a2
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -13554,6 +13554,7 @@ package android.graphics {
  public static class ImageDecoder.ImageInfo {
    method public java.lang.String getMimeType();
    method public android.util.Size getSize();
    method public boolean isAnimated();
  }
  public static class ImageDecoder.IncompleteException extends java.io.IOException {
@@ -14424,6 +14425,22 @@ package android.graphics.drawable {
    method public void onAnimationStart(android.graphics.drawable.Drawable);
  }
  public class AnimatedImageDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Animatable2 {
    ctor public AnimatedImageDrawable();
    method public void clearAnimationCallbacks();
    method public void draw(android.graphics.Canvas);
    method public int getOpacity();
    method public boolean isRunning();
    method public void registerAnimationCallback(android.graphics.drawable.Animatable2.AnimationCallback);
    method public void setAlpha(int);
    method public void setColorFilter(android.graphics.ColorFilter);
    method public void setLoopCount(int);
    method public void start();
    method public void stop();
    method public boolean unregisterAnimationCallback(android.graphics.drawable.Animatable2.AnimationCallback);
    field public static final int LOOP_INFINITE = -1; // 0xffffffff
  }
  public class AnimatedStateListDrawable extends android.graphics.drawable.StateListDrawable {
    ctor public AnimatedStateListDrawable();
    method public void addState(int[], android.graphics.drawable.Drawable, int);
+48 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include "GraphicsJNI.h"
#include "ImageDecoder.h"
#include "core_jni_helpers.h"
#include "Utils.h"

#include <hwui/AnimatedImageDrawable.h>
#include <hwui/Canvas.h>
@@ -28,6 +29,7 @@

using namespace android;

static jmethodID gAnimatedImageDrawable_postOnAnimationEndMethodID;

// Note: jpostProcess holds a handle to the ImageDecoder.
static jlong AnimatedImageDrawable_nCreate(JNIEnv* env, jobject /*clazz*/,
@@ -113,6 +115,9 @@ static jboolean AnimatedImageDrawable_nIsRunning(JNIEnv* env, jobject /*clazz*/,
    return drawable->isRunning();
}

// Java's NOT_RUNNING relies on this being -2.0.
static_assert(SkAnimatedImage::kNotRunning == -2.0);

static jboolean AnimatedImageDrawable_nStart(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
    auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
    return drawable->start();
@@ -123,6 +128,44 @@ static void AnimatedImageDrawable_nStop(JNIEnv* env, jobject /*clazz*/, jlong na
    drawable->stop();
}

// Java's LOOP_INFINITE relies on this being the same.
static_assert(SkCodec::kRepetitionCountInfinite == -1);

static void AnimatedImageDrawable_nSetLoopCount(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
                                                jint loopCount) {
    auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
    drawable->setRepetitionCount(loopCount);
}

class JniAnimationEndListener : public OnAnimationEndListener {
public:
    JniAnimationEndListener(JNIEnv* env, jobject javaObject) {
        LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&mJvm) != JNI_OK);
        mJavaObject = env->NewGlobalRef(javaObject);
    }

    ~JniAnimationEndListener() override {
        auto* env = get_env_or_die(mJvm);
        env->DeleteGlobalRef(mJavaObject);
    }

    void onAnimationEnd() override {
        auto* env = get_env_or_die(mJvm);
        env->CallVoidMethod(mJavaObject, gAnimatedImageDrawable_postOnAnimationEndMethodID);
    }

private:
    JavaVM* mJvm;
    jobject mJavaObject;
};

static void AnimatedImageDrawable_nSetOnAnimationEndListener(JNIEnv* env, jobject /*clazz*/,
                                                             jlong nativePtr, jobject jdrawable) {
    auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
    drawable->setOnAnimationEndListener(std::unique_ptr<OnAnimationEndListener>(
                new JniAnimationEndListener(env, jdrawable)));
}

static long AnimatedImageDrawable_nNativeByteSize(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
    auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
    // FIXME: Report the size of the internal SkBitmap etc.
@@ -139,10 +182,15 @@ static const JNINativeMethod gAnimatedImageDrawableMethods[] = {
    { "nIsRunning",          "(J)Z",                                                         (void*) AnimatedImageDrawable_nIsRunning },
    { "nStart",              "(J)Z",                                                         (void*) AnimatedImageDrawable_nStart },
    { "nStop",               "(J)V",                                                         (void*) AnimatedImageDrawable_nStop },
    { "nSetLoopCount",       "(JI)V",                                                        (void*) AnimatedImageDrawable_nSetLoopCount },
    { "nSetOnAnimationEndListener", "(JLandroid/graphics/drawable/AnimatedImageDrawable;)V", (void*) AnimatedImageDrawable_nSetOnAnimationEndListener },
    { "nNativeByteSize",     "(J)J",                                                         (void*) AnimatedImageDrawable_nNativeByteSize },
};

int register_android_graphics_drawable_AnimatedImageDrawable(JNIEnv* env) {
    jclass animatedImageDrawable_class = FindClassOrDie(env, "android/graphics/drawable/AnimatedImageDrawable");
    gAnimatedImageDrawable_postOnAnimationEndMethodID = GetMethodIDOrDie(env, animatedImageDrawable_class, "postOnAnimationEnd", "()V");

    return android::RegisterMethodsOrDie(env, "android/graphics/drawable/AnimatedImageDrawable",
            gAnimatedImageDrawableMethods, NELEM(gAnimatedImageDrawableMethods));
}
+1 −8
Original line number Diff line number Diff line
#include "ByteBufferStreamAdaptor.h"
#include "core_jni_helpers.h"
#include "Utils.h"

#include <SkStream.h>

@@ -8,14 +9,6 @@ using namespace android;
static jmethodID gByteBuffer_getMethodID;
static jmethodID gByteBuffer_setPositionMethodID;

static JNIEnv* get_env_or_die(JavaVM* jvm) {
    JNIEnv* env;
    if (jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
        LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", jvm);
    }
    return env;
}

class ByteBufferStream : public SkStreamAsset {
private:
    ByteBufferStream(JavaVM* jvm, jobject jbyteBuffer, size_t initialPosition, size_t length,
+2 −11
Original line number Diff line number Diff line
@@ -12,15 +12,6 @@
static jmethodID    gInputStream_readMethodID;
static jmethodID    gInputStream_skipMethodID;

// FIXME: Share with ByteBufferStreamAdaptor.cpp?
static JNIEnv* get_env_or_die(JavaVM* jvm) {
    JNIEnv* env;
    if (jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
        LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", jvm);
    }
    return env;
}

/**
 *  Wrapper for a Java InputStream.
 */
@@ -57,13 +48,13 @@ public:
    }

    ~JavaInputStreamAdaptor() override {
        auto* env = get_env_or_die(fJvm);
        auto* env = android::get_env_or_die(fJvm);
        env->DeleteGlobalRef(fJavaInputStream);
        env->DeleteGlobalRef(fJavaByteArray);
    }

    size_t read(void* buffer, size_t size) override {
        auto* env = get_env_or_die(fJvm);
        auto* env = android::get_env_or_die(fJvm);
        if (!fSwallowExceptions && checkException(env)) {
            // Just in case the caller did not clear from a previous exception.
            return 0;
+8 −0
Original line number Diff line number Diff line
@@ -117,3 +117,11 @@ jobject android::nullObjectReturn(const char msg[]) {
bool android::isSeekable(int descriptor) {
    return ::lseek64(descriptor, 0, SEEK_CUR) != -1;
}

JNIEnv* android::get_env_or_die(JavaVM* jvm) {
    JNIEnv* env;
    if (jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
        LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", jvm);
    }
    return env;
}
Loading