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

Commit 738f827d authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Fixes for animationEnd in AnimatedImageDrawable"

parents b414d51d beaf5d91
Loading
Loading
Loading
Loading
+46 −15
Original line number Diff line number Diff line
@@ -26,10 +26,11 @@
#include <SkPictureRecorder.h>
#include <hwui/AnimatedImageDrawable.h>
#include <hwui/Canvas.h>
#include <utils/Looper.h>

using namespace android;

static jmethodID gAnimatedImageDrawable_postOnAnimationEndMethodID;
static jmethodID gAnimatedImageDrawable_onAnimationEndMethodID;

// Note: jpostProcess holds a handle to the ImageDecoder.
static jlong AnimatedImageDrawable_nCreate(JNIEnv* env, jobject /*clazz*/,
@@ -123,9 +124,9 @@ static jboolean AnimatedImageDrawable_nStart(JNIEnv* env, jobject /*clazz*/, jlo
    return drawable->start();
}

static void AnimatedImageDrawable_nStop(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
static jboolean AnimatedImageDrawable_nStop(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
    auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
    drawable->stop();
    return drawable->stop();
}

// Java's LOOP_INFINITE relies on this being the same.
@@ -137,33 +138,63 @@ static void AnimatedImageDrawable_nSetLoopCount(JNIEnv* env, jobject /*clazz*/,
    drawable->setRepetitionCount(loopCount);
}

class JniAnimationEndListener : public OnAnimationEndListener {
class InvokeListener : public MessageHandler {
public:
    JniAnimationEndListener(JNIEnv* env, jobject javaObject) {
    InvokeListener(JNIEnv* env, jobject javaObject) {
        LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&mJvm) != JNI_OK);
        mJavaObject = env->NewGlobalRef(javaObject);
        // Hold a weak reference to break a cycle that would prevent GC.
        mWeakRef = env->NewWeakGlobalRef(javaObject);
    }

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

    void onAnimationEnd() override {
    virtual void handleMessage(const Message&) override {
        auto* env = get_env_or_die(mJvm);
        env->CallVoidMethod(mJavaObject, gAnimatedImageDrawable_postOnAnimationEndMethodID);
        jobject localRef = env->NewLocalRef(mWeakRef);
        if (localRef) {
            env->CallVoidMethod(localRef, gAnimatedImageDrawable_onAnimationEndMethodID);
        }
    }

private:
    JavaVM* mJvm;
    jobject mJavaObject;
    jweak mWeakRef;
};

class JniAnimationEndListener : public OnAnimationEndListener {
public:
    JniAnimationEndListener(sp<Looper>&& looper, JNIEnv* env, jobject javaObject) {
        mListener = new InvokeListener(env, javaObject);
        mLooper = std::move(looper);
    }

    void onAnimationEnd() override { mLooper->sendMessage(mListener, 0); }

private:
    sp<InvokeListener> mListener;
    sp<Looper> mLooper;
};

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)));
    if (!jdrawable) {
        drawable->setOnAnimationEndListener(nullptr);
    } else {
        sp<Looper> looper = Looper::getForThread();
        if (!looper.get()) {
            doThrowISE(env,
                       "Must set AnimatedImageDrawable's AnimationCallback on a thread with a "
                       "looper!");
            return;
        }

        drawable->setOnAnimationEndListener(
                std::make_unique<JniAnimationEndListener>(std::move(looper), env, jdrawable));
    }
}

static long AnimatedImageDrawable_nNativeByteSize(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
@@ -186,7 +217,7 @@ static const JNINativeMethod gAnimatedImageDrawableMethods[] = {
    { "nSetColorFilter",     "(JJ)V",                                                        (void*) AnimatedImageDrawable_nSetColorFilter },
    { "nIsRunning",          "(J)Z",                                                         (void*) AnimatedImageDrawable_nIsRunning },
    { "nStart",              "(J)Z",                                                         (void*) AnimatedImageDrawable_nStart },
    { "nStop",               "(J)V",                                                         (void*) AnimatedImageDrawable_nStop },
    { "nStop",               "(J)Z",                                                         (void*) AnimatedImageDrawable_nStop },
    { "nSetLoopCount",       "(JI)V",                                                        (void*) AnimatedImageDrawable_nSetLoopCount },
    { "nSetOnAnimationEndListener", "(JLandroid/graphics/drawable/AnimatedImageDrawable;)V", (void*) AnimatedImageDrawable_nSetOnAnimationEndListener },
    { "nNativeByteSize",     "(J)J",                                                         (void*) AnimatedImageDrawable_nNativeByteSize },
@@ -195,7 +226,7 @@ static const JNINativeMethod gAnimatedImageDrawableMethods[] = {

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");
    gAnimatedImageDrawable_onAnimationEndMethodID = GetMethodIDOrDie(env, animatedImageDrawable_class, "onAnimationEnd", "()V");

    return android::RegisterMethodsOrDie(env, "android/graphics/drawable/AnimatedImageDrawable",
            gAnimatedImageDrawableMethods, NELEM(gAnimatedImageDrawableMethods));
+33 −6
Original line number Diff line number Diff line
@@ -348,7 +348,9 @@ public class AnimatedImageDrawable extends Drawable implements Animatable2 {
        if (mState == null) {
            throw new IllegalStateException("called stop on empty AnimatedImageDrawable");
        }
        nStop(mState.mNativePtr);
        if (nStop(mState.mNativePtr)) {
            postOnAnimationEnd();
        }
    }

    // Animatable2 overrides
@@ -365,21 +367,31 @@ public class AnimatedImageDrawable extends Drawable implements Animatable2 {
            nSetOnAnimationEndListener(mState.mNativePtr, this);
        }

        if (!mAnimationCallbacks.contains(callback)) {
            mAnimationCallbacks.add(callback);
        }
    }

    @Override
    public boolean unregisterAnimationCallback(@NonNull AnimationCallback callback) {
        if (callback == null || mAnimationCallbacks == null) {
        if (callback == null || mAnimationCallbacks == null
                || !mAnimationCallbacks.remove(callback)) {
            return false;
        }

        return mAnimationCallbacks.remove(callback);
        if (mAnimationCallbacks.isEmpty()) {
            clearAnimationCallbacks();
        }

        return true;
    }

    @Override
    public void clearAnimationCallbacks() {
        if (mAnimationCallbacks != null) {
            mAnimationCallbacks = null;
            nSetOnAnimationEndListener(mState.mNativePtr, null);
        }
    }

    private void postOnAnimationStart() {
@@ -413,6 +425,21 @@ public class AnimatedImageDrawable extends Drawable implements Animatable2 {
        return mHandler;
    }

    /**
     *  Called by JNI.
     *
     *  The JNI code has already posted this to the thread that created the
     *  callback, so no need to post.
     */
    @SuppressWarnings("unused")
    private void onAnimationEnd() {
        if (mAnimationCallbacks != null) {
            for (Animatable2.AnimationCallback callback : mAnimationCallbacks) {
                callback.onAnimationEnd(this);
            }
        }
    }


    private static native long nCreate(long nativeImageDecoder,
            @Nullable ImageDecoder decoder, int width, int height, Rect cropRect)
@@ -432,7 +459,7 @@ public class AnimatedImageDrawable extends Drawable implements Animatable2 {
    @FastNative
    private static native boolean nStart(long nativePtr);
    @FastNative
    private static native void nStop(long nativePtr);
    private static native boolean nStop(long nativePtr);
    @FastNative
    private static native void nSetLoopCount(long nativePtr, int loopCount);
    // Pass the drawable down to native so it can call onAnimationEnd.
+3 −2
Original line number Diff line number Diff line
@@ -48,8 +48,10 @@ bool AnimatedImageDrawable::start() {
    return true;
}

void AnimatedImageDrawable::stop() {
bool AnimatedImageDrawable::stop() {
    bool wasRunning = mRunning;
    mRunning = false;
    return wasRunning;
}

bool AnimatedImageDrawable::isRunning() {
@@ -180,7 +182,6 @@ void AnimatedImageDrawable::onDraw(SkCanvas* canvas) {
    if (finalFrame) {
        if (mEndListener) {
            mEndListener->onAnimationEnd();
            mEndListener = nullptr;
        }
    }
}
+3 −1
Original line number Diff line number Diff line
@@ -68,7 +68,9 @@ public:
    // Returns true if the animation was started; false otherwise (e.g. it was
    // already running)
    bool start();
    void stop();
    // Returns true if the animation was stopped; false otherwise (e.g. it was
    // already stopped)
    bool stop();
    bool isRunning();
    void setRepetitionCount(int count) { mSkAnimatedImage->setRepetitionCount(count); }