xref: /aosp_15_r20/frameworks/base/libs/hwui/jni/AnimatedImageDrawable.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker  *
4*d57664e9SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker  *
8*d57664e9SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker  *
10*d57664e9SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker  * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker  */
16*d57664e9SAndroid Build Coastguard Worker 
17*d57664e9SAndroid Build Coastguard Worker #include <SkAndroidCodec.h>
18*d57664e9SAndroid Build Coastguard Worker #include <SkAnimatedImage.h>
19*d57664e9SAndroid Build Coastguard Worker #include <SkColorFilter.h>
20*d57664e9SAndroid Build Coastguard Worker #include <SkEncodedImageFormat.h>
21*d57664e9SAndroid Build Coastguard Worker #include <SkPicture.h>
22*d57664e9SAndroid Build Coastguard Worker #include <SkPictureRecorder.h>
23*d57664e9SAndroid Build Coastguard Worker #include <SkRect.h>
24*d57664e9SAndroid Build Coastguard Worker #include <SkRefCnt.h>
25*d57664e9SAndroid Build Coastguard Worker #include <hwui/AnimatedImageDrawable.h>
26*d57664e9SAndroid Build Coastguard Worker #include <hwui/Canvas.h>
27*d57664e9SAndroid Build Coastguard Worker #include <hwui/ImageDecoder.h>
28*d57664e9SAndroid Build Coastguard Worker #ifdef __ANDROID__
29*d57664e9SAndroid Build Coastguard Worker #include <utils/Looper.h>
30*d57664e9SAndroid Build Coastguard Worker #else
31*d57664e9SAndroid Build Coastguard Worker #include "utils/MessageHandler.h"
32*d57664e9SAndroid Build Coastguard Worker #endif
33*d57664e9SAndroid Build Coastguard Worker 
34*d57664e9SAndroid Build Coastguard Worker #include "ColorFilter.h"
35*d57664e9SAndroid Build Coastguard Worker #include "GraphicsJNI.h"
36*d57664e9SAndroid Build Coastguard Worker #include "ImageDecoder.h"
37*d57664e9SAndroid Build Coastguard Worker #include "Utils.h"
38*d57664e9SAndroid Build Coastguard Worker 
39*d57664e9SAndroid Build Coastguard Worker using namespace android;
40*d57664e9SAndroid Build Coastguard Worker 
41*d57664e9SAndroid Build Coastguard Worker static jclass gAnimatedImageDrawableClass;
42*d57664e9SAndroid Build Coastguard Worker static jmethodID gAnimatedImageDrawable_callOnAnimationEndMethodID;
43*d57664e9SAndroid Build Coastguard Worker 
44*d57664e9SAndroid Build Coastguard Worker // Note: jpostProcess holds a handle to the ImageDecoder.
AnimatedImageDrawable_nCreate(JNIEnv * env,jobject,jlong nativeImageDecoder,jobject jpostProcess,jint width,jint height,jlong colorSpaceHandle,jboolean extended,jobject jsubset)45*d57664e9SAndroid Build Coastguard Worker static jlong AnimatedImageDrawable_nCreate(JNIEnv* env, jobject /*clazz*/,
46*d57664e9SAndroid Build Coastguard Worker                                            jlong nativeImageDecoder, jobject jpostProcess,
47*d57664e9SAndroid Build Coastguard Worker                                            jint width, jint height, jlong colorSpaceHandle,
48*d57664e9SAndroid Build Coastguard Worker                                            jboolean extended, jobject jsubset) {
49*d57664e9SAndroid Build Coastguard Worker     if (nativeImageDecoder == 0) {
50*d57664e9SAndroid Build Coastguard Worker         doThrowIOE(env, "Cannot create AnimatedImageDrawable from null!");
51*d57664e9SAndroid Build Coastguard Worker         return 0;
52*d57664e9SAndroid Build Coastguard Worker     }
53*d57664e9SAndroid Build Coastguard Worker 
54*d57664e9SAndroid Build Coastguard Worker     auto* imageDecoder = reinterpret_cast<ImageDecoder*>(nativeImageDecoder);
55*d57664e9SAndroid Build Coastguard Worker     SkIRect subset;
56*d57664e9SAndroid Build Coastguard Worker     if (jsubset) {
57*d57664e9SAndroid Build Coastguard Worker         GraphicsJNI::jrect_to_irect(env, jsubset, &subset);
58*d57664e9SAndroid Build Coastguard Worker     } else {
59*d57664e9SAndroid Build Coastguard Worker         subset = SkIRect::MakeWH(width, height);
60*d57664e9SAndroid Build Coastguard Worker     }
61*d57664e9SAndroid Build Coastguard Worker 
62*d57664e9SAndroid Build Coastguard Worker     bool hasRestoreFrame = false;
63*d57664e9SAndroid Build Coastguard Worker     if (imageDecoder->mCodec->getEncodedFormat() != SkEncodedImageFormat::kWEBP) {
64*d57664e9SAndroid Build Coastguard Worker         const int frameCount = imageDecoder->mCodec->codec()->getFrameCount();
65*d57664e9SAndroid Build Coastguard Worker         for (int i = 0; i < frameCount; ++i) {
66*d57664e9SAndroid Build Coastguard Worker             SkCodec::FrameInfo frameInfo;
67*d57664e9SAndroid Build Coastguard Worker             if (!imageDecoder->mCodec->codec()->getFrameInfo(i, &frameInfo)) {
68*d57664e9SAndroid Build Coastguard Worker                 doThrowIOE(env, "Failed to read frame info!");
69*d57664e9SAndroid Build Coastguard Worker                 return 0;
70*d57664e9SAndroid Build Coastguard Worker             }
71*d57664e9SAndroid Build Coastguard Worker             if (frameInfo.fDisposalMethod == SkCodecAnimation::DisposalMethod::kRestorePrevious) {
72*d57664e9SAndroid Build Coastguard Worker                 hasRestoreFrame = true;
73*d57664e9SAndroid Build Coastguard Worker                 break;
74*d57664e9SAndroid Build Coastguard Worker             }
75*d57664e9SAndroid Build Coastguard Worker         }
76*d57664e9SAndroid Build Coastguard Worker     }
77*d57664e9SAndroid Build Coastguard Worker 
78*d57664e9SAndroid Build Coastguard Worker     auto info = imageDecoder->mCodec->getInfo().makeWH(width, height)
79*d57664e9SAndroid Build Coastguard Worker         .makeColorSpace(GraphicsJNI::getNativeColorSpace(colorSpaceHandle));
80*d57664e9SAndroid Build Coastguard Worker     if (extended) {
81*d57664e9SAndroid Build Coastguard Worker         info = info.makeColorType(kRGBA_F16_SkColorType);
82*d57664e9SAndroid Build Coastguard Worker     }
83*d57664e9SAndroid Build Coastguard Worker 
84*d57664e9SAndroid Build Coastguard Worker     size_t bytesUsed = info.computeMinByteSize();
85*d57664e9SAndroid Build Coastguard Worker     // SkAnimatedImage has one SkBitmap for decoding, plus an extra one if there is a
86*d57664e9SAndroid Build Coastguard Worker     // kRestorePrevious frame. AnimatedImageDrawable has two SkPictures storing the current
87*d57664e9SAndroid Build Coastguard Worker     // frame and the next frame. (The former assumes that the image is animated, and the
88*d57664e9SAndroid Build Coastguard Worker     // latter assumes that it is drawn to a hardware canvas.)
89*d57664e9SAndroid Build Coastguard Worker     bytesUsed *= hasRestoreFrame ? 4 : 3;
90*d57664e9SAndroid Build Coastguard Worker     sk_sp<SkPicture> picture;
91*d57664e9SAndroid Build Coastguard Worker     if (jpostProcess) {
92*d57664e9SAndroid Build Coastguard Worker         SkRect bounds = SkRect::MakeWH(subset.width(), subset.height());
93*d57664e9SAndroid Build Coastguard Worker 
94*d57664e9SAndroid Build Coastguard Worker         SkPictureRecorder recorder;
95*d57664e9SAndroid Build Coastguard Worker         SkCanvas* skcanvas = recorder.beginRecording(bounds);
96*d57664e9SAndroid Build Coastguard Worker         std::unique_ptr<Canvas> canvas(Canvas::create_canvas(skcanvas));
97*d57664e9SAndroid Build Coastguard Worker         postProcessAndRelease(env, jpostProcess, std::move(canvas));
98*d57664e9SAndroid Build Coastguard Worker         if (env->ExceptionCheck()) {
99*d57664e9SAndroid Build Coastguard Worker             return 0;
100*d57664e9SAndroid Build Coastguard Worker         }
101*d57664e9SAndroid Build Coastguard Worker         picture = recorder.finishRecordingAsPicture();
102*d57664e9SAndroid Build Coastguard Worker         bytesUsed += picture->approximateBytesUsed();
103*d57664e9SAndroid Build Coastguard Worker     }
104*d57664e9SAndroid Build Coastguard Worker 
105*d57664e9SAndroid Build Coastguard Worker     SkEncodedImageFormat format = imageDecoder->mCodec->getEncodedFormat();
106*d57664e9SAndroid Build Coastguard Worker     sk_sp<SkAnimatedImage> animatedImg = SkAnimatedImage::Make(std::move(imageDecoder->mCodec),
107*d57664e9SAndroid Build Coastguard Worker                                                                info, subset,
108*d57664e9SAndroid Build Coastguard Worker                                                                std::move(picture));
109*d57664e9SAndroid Build Coastguard Worker     if (!animatedImg) {
110*d57664e9SAndroid Build Coastguard Worker         doThrowIOE(env, "Failed to create drawable");
111*d57664e9SAndroid Build Coastguard Worker         return 0;
112*d57664e9SAndroid Build Coastguard Worker     }
113*d57664e9SAndroid Build Coastguard Worker 
114*d57664e9SAndroid Build Coastguard Worker     bytesUsed += sizeof(animatedImg.get());
115*d57664e9SAndroid Build Coastguard Worker 
116*d57664e9SAndroid Build Coastguard Worker     sk_sp<AnimatedImageDrawable> drawable(
117*d57664e9SAndroid Build Coastguard Worker             new AnimatedImageDrawable(std::move(animatedImg), bytesUsed, format));
118*d57664e9SAndroid Build Coastguard Worker     return reinterpret_cast<jlong>(drawable.release());
119*d57664e9SAndroid Build Coastguard Worker }
120*d57664e9SAndroid Build Coastguard Worker 
AnimatedImageDrawable_destruct(AnimatedImageDrawable * drawable)121*d57664e9SAndroid Build Coastguard Worker static void AnimatedImageDrawable_destruct(AnimatedImageDrawable* drawable) {
122*d57664e9SAndroid Build Coastguard Worker     SkSafeUnref(drawable);
123*d57664e9SAndroid Build Coastguard Worker }
124*d57664e9SAndroid Build Coastguard Worker 
AnimatedImageDrawable_nGetNativeFinalizer(JNIEnv *,jobject)125*d57664e9SAndroid Build Coastguard Worker static jlong AnimatedImageDrawable_nGetNativeFinalizer(JNIEnv* /*env*/, jobject /*clazz*/) {
126*d57664e9SAndroid Build Coastguard Worker     return static_cast<jlong>(reinterpret_cast<uintptr_t>(&AnimatedImageDrawable_destruct));
127*d57664e9SAndroid Build Coastguard Worker }
128*d57664e9SAndroid Build Coastguard Worker 
129*d57664e9SAndroid Build Coastguard Worker // Java's FINISHED relies on this being -1
130*d57664e9SAndroid Build Coastguard Worker static_assert(SkAnimatedImage::kFinished == -1);
131*d57664e9SAndroid Build Coastguard Worker 
AnimatedImageDrawable_nDraw(JNIEnv * env,jobject,jlong nativePtr,jlong canvasPtr)132*d57664e9SAndroid Build Coastguard Worker static jlong AnimatedImageDrawable_nDraw(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
133*d57664e9SAndroid Build Coastguard Worker                                          jlong canvasPtr) {
134*d57664e9SAndroid Build Coastguard Worker     auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
135*d57664e9SAndroid Build Coastguard Worker     auto* canvas = reinterpret_cast<Canvas*>(canvasPtr);
136*d57664e9SAndroid Build Coastguard Worker     return (jlong) canvas->drawAnimatedImage(drawable);
137*d57664e9SAndroid Build Coastguard Worker }
138*d57664e9SAndroid Build Coastguard Worker 
AnimatedImageDrawable_nSetAlpha(JNIEnv * env,jobject,jlong nativePtr,jint alpha)139*d57664e9SAndroid Build Coastguard Worker static void AnimatedImageDrawable_nSetAlpha(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
140*d57664e9SAndroid Build Coastguard Worker                                             jint alpha) {
141*d57664e9SAndroid Build Coastguard Worker     auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
142*d57664e9SAndroid Build Coastguard Worker     drawable->setStagingAlpha(alpha);
143*d57664e9SAndroid Build Coastguard Worker }
144*d57664e9SAndroid Build Coastguard Worker 
AnimatedImageDrawable_nGetAlpha(JNIEnv * env,jobject,jlong nativePtr)145*d57664e9SAndroid Build Coastguard Worker static jlong AnimatedImageDrawable_nGetAlpha(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
146*d57664e9SAndroid Build Coastguard Worker     auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
147*d57664e9SAndroid Build Coastguard Worker     return drawable->getStagingAlpha();
148*d57664e9SAndroid Build Coastguard Worker }
149*d57664e9SAndroid Build Coastguard Worker 
AnimatedImageDrawable_nSetColorFilter(JNIEnv * env,jobject,jlong nativePtr,jlong nativeFilter)150*d57664e9SAndroid Build Coastguard Worker static void AnimatedImageDrawable_nSetColorFilter(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
151*d57664e9SAndroid Build Coastguard Worker                                                   jlong nativeFilter) {
152*d57664e9SAndroid Build Coastguard Worker     auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
153*d57664e9SAndroid Build Coastguard Worker     auto filter = uirenderer::ColorFilter::fromJava(nativeFilter);
154*d57664e9SAndroid Build Coastguard Worker     auto skColorFilter = filter != nullptr ? filter->getInstance() : sk_sp<SkColorFilter>();
155*d57664e9SAndroid Build Coastguard Worker     drawable->setStagingColorFilter(skColorFilter);
156*d57664e9SAndroid Build Coastguard Worker }
157*d57664e9SAndroid Build Coastguard Worker 
AnimatedImageDrawable_nIsRunning(JNIEnv * env,jobject,jlong nativePtr)158*d57664e9SAndroid Build Coastguard Worker static jboolean AnimatedImageDrawable_nIsRunning(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
159*d57664e9SAndroid Build Coastguard Worker     auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
160*d57664e9SAndroid Build Coastguard Worker     return drawable->isRunning();
161*d57664e9SAndroid Build Coastguard Worker }
162*d57664e9SAndroid Build Coastguard Worker 
AnimatedImageDrawable_nStart(JNIEnv * env,jobject,jlong nativePtr)163*d57664e9SAndroid Build Coastguard Worker static jboolean AnimatedImageDrawable_nStart(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
164*d57664e9SAndroid Build Coastguard Worker     auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
165*d57664e9SAndroid Build Coastguard Worker     return drawable->start();
166*d57664e9SAndroid Build Coastguard Worker }
167*d57664e9SAndroid Build Coastguard Worker 
AnimatedImageDrawable_nStop(JNIEnv * env,jobject,jlong nativePtr)168*d57664e9SAndroid Build Coastguard Worker static jboolean AnimatedImageDrawable_nStop(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
169*d57664e9SAndroid Build Coastguard Worker     auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
170*d57664e9SAndroid Build Coastguard Worker     return drawable->stop();
171*d57664e9SAndroid Build Coastguard Worker }
172*d57664e9SAndroid Build Coastguard Worker 
173*d57664e9SAndroid Build Coastguard Worker // Java's LOOP_INFINITE relies on this being the same.
174*d57664e9SAndroid Build Coastguard Worker static_assert(SkCodec::kRepetitionCountInfinite == -1);
175*d57664e9SAndroid Build Coastguard Worker 
AnimatedImageDrawable_nGetRepeatCount(JNIEnv * env,jobject,jlong nativePtr)176*d57664e9SAndroid Build Coastguard Worker static jint AnimatedImageDrawable_nGetRepeatCount(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
177*d57664e9SAndroid Build Coastguard Worker     auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
178*d57664e9SAndroid Build Coastguard Worker     return drawable->getRepetitionCount();
179*d57664e9SAndroid Build Coastguard Worker }
180*d57664e9SAndroid Build Coastguard Worker 
AnimatedImageDrawable_nSetRepeatCount(JNIEnv * env,jobject,jlong nativePtr,jint loopCount)181*d57664e9SAndroid Build Coastguard Worker static void AnimatedImageDrawable_nSetRepeatCount(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
182*d57664e9SAndroid Build Coastguard Worker                                                   jint loopCount) {
183*d57664e9SAndroid Build Coastguard Worker     auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
184*d57664e9SAndroid Build Coastguard Worker     drawable->setRepetitionCount(loopCount);
185*d57664e9SAndroid Build Coastguard Worker }
186*d57664e9SAndroid Build Coastguard Worker 
187*d57664e9SAndroid Build Coastguard Worker class InvokeListener : public MessageHandler {
188*d57664e9SAndroid Build Coastguard Worker public:
InvokeListener(JNIEnv * env,jobject javaObject)189*d57664e9SAndroid Build Coastguard Worker     InvokeListener(JNIEnv* env, jobject javaObject) {
190*d57664e9SAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&mJvm) != JNI_OK);
191*d57664e9SAndroid Build Coastguard Worker         mCallbackRef = env->NewGlobalRef(javaObject);
192*d57664e9SAndroid Build Coastguard Worker     }
193*d57664e9SAndroid Build Coastguard Worker 
~InvokeListener()194*d57664e9SAndroid Build Coastguard Worker     ~InvokeListener() override {
195*d57664e9SAndroid Build Coastguard Worker         auto* env = requireEnv(mJvm);
196*d57664e9SAndroid Build Coastguard Worker         env->DeleteGlobalRef(mCallbackRef);
197*d57664e9SAndroid Build Coastguard Worker     }
198*d57664e9SAndroid Build Coastguard Worker 
handleMessage(const Message &)199*d57664e9SAndroid Build Coastguard Worker     virtual void handleMessage(const Message&) override {
200*d57664e9SAndroid Build Coastguard Worker         auto* env = get_env_or_die(mJvm);
201*d57664e9SAndroid Build Coastguard Worker         env->CallStaticVoidMethod(gAnimatedImageDrawableClass,
202*d57664e9SAndroid Build Coastguard Worker                                   gAnimatedImageDrawable_callOnAnimationEndMethodID, mCallbackRef);
203*d57664e9SAndroid Build Coastguard Worker     }
204*d57664e9SAndroid Build Coastguard Worker 
205*d57664e9SAndroid Build Coastguard Worker private:
206*d57664e9SAndroid Build Coastguard Worker     JavaVM* mJvm;
207*d57664e9SAndroid Build Coastguard Worker     jobject mCallbackRef;
208*d57664e9SAndroid Build Coastguard Worker };
209*d57664e9SAndroid Build Coastguard Worker 
210*d57664e9SAndroid Build Coastguard Worker class JniAnimationEndListener : public OnAnimationEndListener {
211*d57664e9SAndroid Build Coastguard Worker #ifdef __ANDROID__
212*d57664e9SAndroid Build Coastguard Worker public:
JniAnimationEndListener(sp<Looper> && looper,JNIEnv * env,jobject javaObject)213*d57664e9SAndroid Build Coastguard Worker     JniAnimationEndListener(sp<Looper>&& looper, JNIEnv* env, jobject javaObject) {
214*d57664e9SAndroid Build Coastguard Worker         mListener = new InvokeListener(env, javaObject);
215*d57664e9SAndroid Build Coastguard Worker         mLooper = std::move(looper);
216*d57664e9SAndroid Build Coastguard Worker     }
217*d57664e9SAndroid Build Coastguard Worker 
onAnimationEnd()218*d57664e9SAndroid Build Coastguard Worker     void onAnimationEnd() override { mLooper->sendMessage(mListener, 0); }
219*d57664e9SAndroid Build Coastguard Worker 
220*d57664e9SAndroid Build Coastguard Worker private:
221*d57664e9SAndroid Build Coastguard Worker     sp<InvokeListener> mListener;
222*d57664e9SAndroid Build Coastguard Worker     sp<Looper> mLooper;
223*d57664e9SAndroid Build Coastguard Worker #else
224*d57664e9SAndroid Build Coastguard Worker public:
225*d57664e9SAndroid Build Coastguard Worker     JniAnimationEndListener(JNIEnv* env, jobject javaObject) {
226*d57664e9SAndroid Build Coastguard Worker         mListener = new InvokeListener(env, javaObject);
227*d57664e9SAndroid Build Coastguard Worker     }
228*d57664e9SAndroid Build Coastguard Worker 
229*d57664e9SAndroid Build Coastguard Worker     void onAnimationEnd() override { mListener->handleMessage(0); }
230*d57664e9SAndroid Build Coastguard Worker 
231*d57664e9SAndroid Build Coastguard Worker private:
232*d57664e9SAndroid Build Coastguard Worker     sp<InvokeListener> mListener;
233*d57664e9SAndroid Build Coastguard Worker #endif
234*d57664e9SAndroid Build Coastguard Worker };
235*d57664e9SAndroid Build Coastguard Worker 
AnimatedImageDrawable_nSetOnAnimationEndListener(JNIEnv * env,jobject,jlong nativePtr,jobject jdrawable)236*d57664e9SAndroid Build Coastguard Worker static void AnimatedImageDrawable_nSetOnAnimationEndListener(JNIEnv* env, jobject /*clazz*/,
237*d57664e9SAndroid Build Coastguard Worker                                                              jlong nativePtr, jobject jdrawable) {
238*d57664e9SAndroid Build Coastguard Worker     auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
239*d57664e9SAndroid Build Coastguard Worker     if (!jdrawable) {
240*d57664e9SAndroid Build Coastguard Worker         drawable->setOnAnimationEndListener(nullptr);
241*d57664e9SAndroid Build Coastguard Worker     } else {
242*d57664e9SAndroid Build Coastguard Worker #ifdef __ANDROID__
243*d57664e9SAndroid Build Coastguard Worker         sp<Looper> looper = Looper::getForThread();
244*d57664e9SAndroid Build Coastguard Worker         if (!looper.get()) {
245*d57664e9SAndroid Build Coastguard Worker             doThrowISE(env,
246*d57664e9SAndroid Build Coastguard Worker                        "Must set AnimatedImageDrawable's AnimationCallback on a thread with a "
247*d57664e9SAndroid Build Coastguard Worker                        "looper!");
248*d57664e9SAndroid Build Coastguard Worker             return;
249*d57664e9SAndroid Build Coastguard Worker         }
250*d57664e9SAndroid Build Coastguard Worker 
251*d57664e9SAndroid Build Coastguard Worker         drawable->setOnAnimationEndListener(
252*d57664e9SAndroid Build Coastguard Worker                 std::make_unique<JniAnimationEndListener>(std::move(looper), env, jdrawable));
253*d57664e9SAndroid Build Coastguard Worker #else
254*d57664e9SAndroid Build Coastguard Worker         drawable->setOnAnimationEndListener(
255*d57664e9SAndroid Build Coastguard Worker                 std::make_unique<JniAnimationEndListener>(env, jdrawable));
256*d57664e9SAndroid Build Coastguard Worker #endif
257*d57664e9SAndroid Build Coastguard Worker     }
258*d57664e9SAndroid Build Coastguard Worker }
259*d57664e9SAndroid Build Coastguard Worker 
AnimatedImageDrawable_nNativeByteSize(JNIEnv * env,jobject,jlong nativePtr)260*d57664e9SAndroid Build Coastguard Worker static jlong AnimatedImageDrawable_nNativeByteSize(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
261*d57664e9SAndroid Build Coastguard Worker     auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
262*d57664e9SAndroid Build Coastguard Worker     return drawable->byteSize();
263*d57664e9SAndroid Build Coastguard Worker }
264*d57664e9SAndroid Build Coastguard Worker 
AnimatedImageDrawable_nSetMirrored(JNIEnv * env,jobject,jlong nativePtr,jboolean mirrored)265*d57664e9SAndroid Build Coastguard Worker static void AnimatedImageDrawable_nSetMirrored(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
266*d57664e9SAndroid Build Coastguard Worker                                                jboolean mirrored) {
267*d57664e9SAndroid Build Coastguard Worker     auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
268*d57664e9SAndroid Build Coastguard Worker     drawable->setStagingMirrored(mirrored);
269*d57664e9SAndroid Build Coastguard Worker }
270*d57664e9SAndroid Build Coastguard Worker 
AnimatedImageDrawable_nSetBounds(JNIEnv * env,jobject,jlong nativePtr,jobject jrect)271*d57664e9SAndroid Build Coastguard Worker static void AnimatedImageDrawable_nSetBounds(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
272*d57664e9SAndroid Build Coastguard Worker                                              jobject jrect) {
273*d57664e9SAndroid Build Coastguard Worker     auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
274*d57664e9SAndroid Build Coastguard Worker     SkRect rect;
275*d57664e9SAndroid Build Coastguard Worker     GraphicsJNI::jrect_to_rect(env, jrect, &rect);
276*d57664e9SAndroid Build Coastguard Worker     drawable->setStagingBounds(rect);
277*d57664e9SAndroid Build Coastguard Worker }
278*d57664e9SAndroid Build Coastguard Worker 
AnimatedImageDrawable_nSetFilterBitmap(JNIEnv * env,jobject,jlong nativePtr,jboolean filterBitmap)279*d57664e9SAndroid Build Coastguard Worker static jboolean AnimatedImageDrawable_nSetFilterBitmap(JNIEnv* env, jobject /*clazz*/,
280*d57664e9SAndroid Build Coastguard Worker                                                        jlong nativePtr, jboolean filterBitmap) {
281*d57664e9SAndroid Build Coastguard Worker     auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
282*d57664e9SAndroid Build Coastguard Worker     return drawable->setFilterBitmap(filterBitmap);
283*d57664e9SAndroid Build Coastguard Worker }
284*d57664e9SAndroid Build Coastguard Worker 
AnimatedImageDrawable_nGetFilterBitmap(JNIEnv * env,jobject,jlong nativePtr)285*d57664e9SAndroid Build Coastguard Worker static jboolean AnimatedImageDrawable_nGetFilterBitmap(JNIEnv* env, jobject /*clazz*/,
286*d57664e9SAndroid Build Coastguard Worker                                                        jlong nativePtr) {
287*d57664e9SAndroid Build Coastguard Worker     auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
288*d57664e9SAndroid Build Coastguard Worker     return drawable->getFilterBitmap();
289*d57664e9SAndroid Build Coastguard Worker }
290*d57664e9SAndroid Build Coastguard Worker 
291*d57664e9SAndroid Build Coastguard Worker static const JNINativeMethod gAnimatedImageDrawableMethods[] = {
292*d57664e9SAndroid Build Coastguard Worker         {"nCreate", "(JLandroid/graphics/ImageDecoder;IIJZLandroid/graphics/Rect;)J",
293*d57664e9SAndroid Build Coastguard Worker          (void*)AnimatedImageDrawable_nCreate},
294*d57664e9SAndroid Build Coastguard Worker         {"nGetNativeFinalizer", "()J", (void*)AnimatedImageDrawable_nGetNativeFinalizer},
295*d57664e9SAndroid Build Coastguard Worker         {"nDraw", "(JJ)J", (void*)AnimatedImageDrawable_nDraw},
296*d57664e9SAndroid Build Coastguard Worker         {"nSetAlpha", "(JI)V", (void*)AnimatedImageDrawable_nSetAlpha},
297*d57664e9SAndroid Build Coastguard Worker         {"nGetAlpha", "(J)I", (void*)AnimatedImageDrawable_nGetAlpha},
298*d57664e9SAndroid Build Coastguard Worker         {"nSetColorFilter", "(JJ)V", (void*)AnimatedImageDrawable_nSetColorFilter},
299*d57664e9SAndroid Build Coastguard Worker         {"nIsRunning", "(J)Z", (void*)AnimatedImageDrawable_nIsRunning},
300*d57664e9SAndroid Build Coastguard Worker         {"nStart", "(J)Z", (void*)AnimatedImageDrawable_nStart},
301*d57664e9SAndroid Build Coastguard Worker         {"nStop", "(J)Z", (void*)AnimatedImageDrawable_nStop},
302*d57664e9SAndroid Build Coastguard Worker         {"nGetRepeatCount", "(J)I", (void*)AnimatedImageDrawable_nGetRepeatCount},
303*d57664e9SAndroid Build Coastguard Worker         {"nSetRepeatCount", "(JI)V", (void*)AnimatedImageDrawable_nSetRepeatCount},
304*d57664e9SAndroid Build Coastguard Worker         {"nSetOnAnimationEndListener", "(JLjava/lang/ref/WeakReference;)V",
305*d57664e9SAndroid Build Coastguard Worker          (void*)AnimatedImageDrawable_nSetOnAnimationEndListener},
306*d57664e9SAndroid Build Coastguard Worker         {"nNativeByteSize", "(J)J", (void*)AnimatedImageDrawable_nNativeByteSize},
307*d57664e9SAndroid Build Coastguard Worker         {"nSetMirrored", "(JZ)V", (void*)AnimatedImageDrawable_nSetMirrored},
308*d57664e9SAndroid Build Coastguard Worker         {"nSetBounds", "(JLandroid/graphics/Rect;)V", (void*)AnimatedImageDrawable_nSetBounds},
309*d57664e9SAndroid Build Coastguard Worker         {"nSetFilterBitmap", "(JZ)Z", (void*)AnimatedImageDrawable_nSetFilterBitmap},
310*d57664e9SAndroid Build Coastguard Worker         {"nGetFilterBitmap", "(J)Z", (void*)AnimatedImageDrawable_nGetFilterBitmap},
311*d57664e9SAndroid Build Coastguard Worker };
312*d57664e9SAndroid Build Coastguard Worker 
register_android_graphics_drawable_AnimatedImageDrawable(JNIEnv * env)313*d57664e9SAndroid Build Coastguard Worker int register_android_graphics_drawable_AnimatedImageDrawable(JNIEnv* env) {
314*d57664e9SAndroid Build Coastguard Worker     gAnimatedImageDrawableClass = reinterpret_cast<jclass>(env->NewGlobalRef(
315*d57664e9SAndroid Build Coastguard Worker             FindClassOrDie(env, "android/graphics/drawable/AnimatedImageDrawable")));
316*d57664e9SAndroid Build Coastguard Worker     gAnimatedImageDrawable_callOnAnimationEndMethodID =
317*d57664e9SAndroid Build Coastguard Worker             GetStaticMethodIDOrDie(env, gAnimatedImageDrawableClass, "callOnAnimationEnd",
318*d57664e9SAndroid Build Coastguard Worker                                    "(Ljava/lang/ref/WeakReference;)V");
319*d57664e9SAndroid Build Coastguard Worker 
320*d57664e9SAndroid Build Coastguard Worker     return android::RegisterMethodsOrDie(env, "android/graphics/drawable/AnimatedImageDrawable",
321*d57664e9SAndroid Build Coastguard Worker             gAnimatedImageDrawableMethods, NELEM(gAnimatedImageDrawableMethods));
322*d57664e9SAndroid Build Coastguard Worker }
323*d57664e9SAndroid Build Coastguard Worker 
324