1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#define LOG_TAG "OpenGLRenderer"
17
18#include "android/log.h"
19
20#include "jni.h"
21#include "GraphicsJNI.h"
22#include "core_jni_helpers.h"
23
24#include "Animator.h"
25#include "Interpolator.h"
26#include "PropertyValuesAnimatorSet.h"
27#include "PropertyValuesHolder.h"
28#include "VectorDrawable.h"
29
30namespace android {
31using namespace uirenderer;
32using namespace VectorDrawable;
33
34static struct {
35    jclass clazz;
36    jmethodID callOnFinished;
37} gVectorDrawableAnimatorClassInfo;
38
39static JNIEnv* getEnv(JavaVM* vm) {
40    JNIEnv* env;
41    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
42        return 0;
43    }
44    return env;
45}
46
47static AnimationListener* createAnimationListener(JNIEnv* env, jobject finishListener, jint id) {
48    class AnimationListenerBridge : public AnimationListener {
49    public:
50        AnimationListenerBridge(JNIEnv* env, jobject finishListener, jint id) {
51            mFinishListener = env->NewGlobalRef(finishListener);
52            env->GetJavaVM(&mJvm);
53            mId = id;
54        }
55
56        virtual ~AnimationListenerBridge() {
57            if (mFinishListener) {
58                onAnimationFinished(NULL);
59            }
60        }
61
62        virtual void onAnimationFinished(BaseRenderNodeAnimator*) {
63            LOG_ALWAYS_FATAL_IF(!mFinishListener, "Finished listener twice?");
64            JNIEnv* env = getEnv(mJvm);
65            env->CallStaticVoidMethod(
66                    gVectorDrawableAnimatorClassInfo.clazz,
67                    gVectorDrawableAnimatorClassInfo.callOnFinished,
68                    mFinishListener, mId);
69            releaseJavaObject();
70        }
71
72    private:
73        void releaseJavaObject() {
74            JNIEnv* env = getEnv(mJvm);
75            env->DeleteGlobalRef(mFinishListener);
76            mFinishListener = NULL;
77        }
78
79        JavaVM* mJvm;
80        jobject mFinishListener;
81        jint mId;
82    };
83    return new AnimationListenerBridge(env, finishListener, id);
84}
85
86static void addAnimator(JNIEnv*, jobject, jlong animatorSetPtr, jlong propertyHolderPtr,
87        jlong interpolatorPtr, jlong startDelay, jlong duration, jint repeatCount,
88        jint repeatMode) {
89    PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorSetPtr);
90    PropertyValuesHolder* holder = reinterpret_cast<PropertyValuesHolder*>(propertyHolderPtr);
91    Interpolator* interpolator = reinterpret_cast<Interpolator*>(interpolatorPtr);
92    RepeatMode mode = static_cast<RepeatMode>(repeatMode);
93    set->addPropertyAnimator(holder, interpolator, startDelay, duration, repeatCount, mode);
94}
95
96static jlong createAnimatorSet(JNIEnv*, jobject) {
97    PropertyValuesAnimatorSet* animatorSet = new PropertyValuesAnimatorSet();
98    return reinterpret_cast<jlong>(animatorSet);
99}
100
101static void setVectorDrawableTarget(JNIEnv*, jobject,jlong animatorPtr, jlong vectorDrawablePtr) {
102    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(vectorDrawablePtr);
103    PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorPtr);
104    set->setVectorDrawable(tree);
105}
106
107static jlong createGroupPropertyHolder(JNIEnv*, jobject, jlong nativePtr, jint propertyId,
108        jfloat startValue, jfloat endValue) {
109    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(nativePtr);
110    GroupPropertyValuesHolder* newHolder = new GroupPropertyValuesHolder(group, propertyId,
111            startValue, endValue);
112    return reinterpret_cast<jlong>(newHolder);
113}
114
115static jlong createPathDataPropertyHolder(JNIEnv*, jobject, jlong nativePtr, jlong startValuePtr,
116        jlong endValuePtr) {
117    VectorDrawable::Path* path = reinterpret_cast<VectorDrawable::Path*>(nativePtr);
118    PathData* startData = reinterpret_cast<PathData*>(startValuePtr);
119    PathData* endData = reinterpret_cast<PathData*>(endValuePtr);
120    PathDataPropertyValuesHolder* newHolder = new PathDataPropertyValuesHolder(path,
121            startData, endData);
122    return reinterpret_cast<jlong>(newHolder);
123}
124
125static jlong createPathColorPropertyHolder(JNIEnv*, jobject, jlong nativePtr, jint propertyId,
126        int startValue, jint endValue) {
127    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(nativePtr);
128    FullPathColorPropertyValuesHolder* newHolder = new FullPathColorPropertyValuesHolder(fullPath,
129            propertyId, startValue, endValue);
130    return reinterpret_cast<jlong>(newHolder);
131}
132
133static jlong createPathPropertyHolder(JNIEnv*, jobject, jlong nativePtr, jint propertyId,
134        float startValue, jfloat endValue) {
135    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(nativePtr);
136    FullPathPropertyValuesHolder* newHolder = new FullPathPropertyValuesHolder(fullPath,
137            propertyId, startValue, endValue);
138    return reinterpret_cast<jlong>(newHolder);
139}
140
141static jlong createRootAlphaPropertyHolder(JNIEnv*, jobject, jlong nativePtr, jfloat startValue,
142        float endValue) {
143    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(nativePtr);
144    RootAlphaPropertyValuesHolder* newHolder = new RootAlphaPropertyValuesHolder(tree,
145            startValue, endValue);
146    return reinterpret_cast<jlong>(newHolder);
147}
148static void setFloatPropertyHolderData(JNIEnv* env, jobject, jlong propertyHolderPtr,
149        jfloatArray srcData, jint length) {
150    jfloat* propertyData = env->GetFloatArrayElements(srcData, nullptr);
151    PropertyValuesHolderImpl<float>* holder =
152            reinterpret_cast<PropertyValuesHolderImpl<float>*>(propertyHolderPtr);
153    holder->setPropertyDataSource(propertyData, length);
154    env->ReleaseFloatArrayElements(srcData, propertyData, JNI_ABORT);
155}
156
157static void setIntPropertyHolderData(JNIEnv* env, jobject, jlong propertyHolderPtr,
158        jintArray srcData, jint length) {
159    jint* propertyData = env->GetIntArrayElements(srcData, nullptr);
160    PropertyValuesHolderImpl<int>* holder =
161            reinterpret_cast<PropertyValuesHolderImpl<int>*>(propertyHolderPtr);
162    holder->setPropertyDataSource(propertyData, length);
163    env->ReleaseIntArrayElements(srcData, propertyData, JNI_ABORT);
164}
165
166static void start(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener, jint id) {
167    PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorSetPtr);
168    AnimationListener* listener = createAnimationListener(env, finishListener, id);
169    set->start(listener);
170}
171
172static void reverse(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener, jint id) {
173    PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorSetPtr);
174    AnimationListener* listener = createAnimationListener(env, finishListener, id);
175    set->reverse(listener);
176}
177
178static void end(JNIEnv*, jobject, jlong animatorSetPtr) {
179    PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorSetPtr);
180    set->end();
181}
182
183static void reset(JNIEnv*, jobject, jlong animatorSetPtr) {
184    PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorSetPtr);
185    set->reset();
186}
187
188static const JNINativeMethod gMethods[] = {
189    {"nCreateAnimatorSet", "()J", (void*)createAnimatorSet},
190    {"nSetVectorDrawableTarget", "(JJ)V", (void*)setVectorDrawableTarget},
191    {"nAddAnimator", "(JJJJJII)V", (void*)addAnimator},
192    {"nSetPropertyHolderData", "(J[FI)V", (void*)setFloatPropertyHolderData},
193    {"nSetPropertyHolderData", "(J[II)V", (void*)setIntPropertyHolderData},
194    {"nStart", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V", (void*)start},
195    {"nReverse", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V", (void*)reverse},
196
197    // ------------- @FastNative -------------------
198
199    {"nCreateGroupPropertyHolder", "(JIFF)J", (void*)createGroupPropertyHolder},
200    {"nCreatePathDataPropertyHolder", "(JJJ)J", (void*)createPathDataPropertyHolder},
201    {"nCreatePathColorPropertyHolder", "(JIII)J", (void*)createPathColorPropertyHolder},
202    {"nCreatePathPropertyHolder", "(JIFF)J", (void*)createPathPropertyHolder},
203    {"nCreateRootAlphaPropertyHolder", "(JFF)J", (void*)createRootAlphaPropertyHolder},
204    {"nEnd", "(J)V", (void*)end},
205    {"nReset", "(J)V", (void*)reset},
206};
207
208const char* const kClassPathName = "android/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT";
209int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env) {
210    gVectorDrawableAnimatorClassInfo.clazz = FindClassOrDie(env, kClassPathName);
211    gVectorDrawableAnimatorClassInfo.clazz = MakeGlobalRefOrDie(env,
212            gVectorDrawableAnimatorClassInfo.clazz);
213
214    gVectorDrawableAnimatorClassInfo.callOnFinished = GetStaticMethodIDOrDie(
215            env, gVectorDrawableAnimatorClassInfo.clazz, "callOnFinished",
216            "(Landroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V");
217    return RegisterMethodsOrDie(env, "android/graphics/drawable/AnimatedVectorDrawable",
218            gMethods, NELEM(gMethods));
219}
220
221}; // namespace android
222