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