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