1/* 2 * Copyright (C) 2013 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#define LOG_TAG "OpenGLRenderer" 18 19#include "jni.h" 20#include "GraphicsJNI.h" 21#include <nativehelper/JNIHelp.h> 22#include <android_runtime/AndroidRuntime.h> 23 24#include <Animator.h> 25#include <Interpolator.h> 26#include <RenderProperties.h> 27 28#include "core_jni_helpers.h" 29 30namespace android { 31 32using namespace uirenderer; 33 34static struct { 35 jclass clazz; 36 37 jmethodID callOnFinished; 38} gRenderNodeAnimatorClassInfo; 39 40static JNIEnv* getEnv(JavaVM* vm) { 41 JNIEnv* env; 42 if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { 43 return 0; 44 } 45 return env; 46} 47 48class AnimationListenerLifecycleChecker : public AnimationListener { 49public: 50 virtual void onAnimationFinished(BaseRenderNodeAnimator* animator) { 51 LOG_ALWAYS_FATAL("Lifecycle failure, nStart(%p) wasn't called", animator); 52 } 53}; 54 55static AnimationListenerLifecycleChecker sLifecycleChecker; 56 57class AnimationListenerBridge : public AnimationListener { 58public: 59 // This holds a strong reference to a Java WeakReference<T> object. This avoids 60 // cyclic-references-of-doom. If you think "I know, just use NewWeakGlobalRef!" 61 // then you end up with basically a PhantomReference, which is totally not 62 // what we want. 63 AnimationListenerBridge(JNIEnv* env, jobject finishListener) { 64 mFinishListener = env->NewGlobalRef(finishListener); 65 env->GetJavaVM(&mJvm); 66 } 67 68 virtual ~AnimationListenerBridge() { 69 if (mFinishListener) { 70 onAnimationFinished(NULL); 71 } 72 } 73 74 virtual void onAnimationFinished(BaseRenderNodeAnimator*) { 75 LOG_ALWAYS_FATAL_IF(!mFinishListener, "Finished listener twice?"); 76 JNIEnv* env = getEnv(mJvm); 77 env->CallStaticVoidMethod( 78 gRenderNodeAnimatorClassInfo.clazz, 79 gRenderNodeAnimatorClassInfo.callOnFinished, 80 mFinishListener); 81 releaseJavaObject(); 82 } 83 84private: 85 void releaseJavaObject() { 86 JNIEnv* env = getEnv(mJvm); 87 env->DeleteGlobalRef(mFinishListener); 88 mFinishListener = NULL; 89 } 90 91 JavaVM* mJvm; 92 jobject mFinishListener; 93}; 94 95static inline RenderPropertyAnimator::RenderProperty toRenderProperty(jint property) { 96 LOG_ALWAYS_FATAL_IF(property < 0 || property > RenderPropertyAnimator::ALPHA, 97 "Invalid property %d", property); 98 return static_cast<RenderPropertyAnimator::RenderProperty>(property); 99} 100 101static inline CanvasPropertyPaintAnimator::PaintField toPaintField(jint field) { 102 LOG_ALWAYS_FATAL_IF(field < 0 103 || field > CanvasPropertyPaintAnimator::ALPHA, 104 "Invalid paint field %d", field); 105 return static_cast<CanvasPropertyPaintAnimator::PaintField>(field); 106} 107 108static jlong createAnimator(JNIEnv* env, jobject clazz, 109 jint propertyRaw, jfloat finalValue) { 110 RenderPropertyAnimator::RenderProperty property = toRenderProperty(propertyRaw); 111 BaseRenderNodeAnimator* animator = new RenderPropertyAnimator(property, finalValue); 112 animator->setListener(&sLifecycleChecker); 113 return reinterpret_cast<jlong>( animator ); 114} 115 116static jlong createCanvasPropertyFloatAnimator(JNIEnv* env, jobject clazz, 117 jlong canvasPropertyPtr, jfloat finalValue) { 118 CanvasPropertyPrimitive* canvasProperty = reinterpret_cast<CanvasPropertyPrimitive*>(canvasPropertyPtr); 119 BaseRenderNodeAnimator* animator = new CanvasPropertyPrimitiveAnimator(canvasProperty, finalValue); 120 animator->setListener(&sLifecycleChecker); 121 return reinterpret_cast<jlong>( animator ); 122} 123 124static jlong createCanvasPropertyPaintAnimator(JNIEnv* env, jobject clazz, 125 jlong canvasPropertyPtr, jint paintFieldRaw, 126 jfloat finalValue) { 127 CanvasPropertyPaint* canvasProperty = reinterpret_cast<CanvasPropertyPaint*>(canvasPropertyPtr); 128 CanvasPropertyPaintAnimator::PaintField paintField = toPaintField(paintFieldRaw); 129 BaseRenderNodeAnimator* animator = new CanvasPropertyPaintAnimator( 130 canvasProperty, paintField, finalValue); 131 animator->setListener(&sLifecycleChecker); 132 return reinterpret_cast<jlong>( animator ); 133} 134 135static jlong createRevealAnimator(JNIEnv* env, jobject clazz, 136 jint centerX, jint centerY, jfloat startRadius, jfloat endRadius) { 137 BaseRenderNodeAnimator* animator = new RevealAnimator(centerX, centerY, startRadius, endRadius); 138 animator->setListener(&sLifecycleChecker); 139 return reinterpret_cast<jlong>( animator ); 140} 141 142static void setStartValue(JNIEnv* env, jobject clazz, jlong animatorPtr, jfloat startValue) { 143 BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr); 144 animator->setStartValue(startValue); 145} 146 147static void setDuration(JNIEnv* env, jobject clazz, jlong animatorPtr, jlong duration) { 148 LOG_ALWAYS_FATAL_IF(duration < 0, "Duration cannot be negative"); 149 BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr); 150 animator->setDuration(duration); 151} 152 153static jlong getDuration(JNIEnv* env, jobject clazz, jlong animatorPtr) { 154 BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr); 155 return static_cast<jlong>(animator->duration()); 156} 157 158static void setStartDelay(JNIEnv* env, jobject clazz, jlong animatorPtr, jlong startDelay) { 159 LOG_ALWAYS_FATAL_IF(startDelay < 0, "Start delay cannot be negative"); 160 BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr); 161 animator->setStartDelay(startDelay); 162} 163 164static void setInterpolator(JNIEnv* env, jobject clazz, jlong animatorPtr, jlong interpolatorPtr) { 165 BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr); 166 Interpolator* interpolator = reinterpret_cast<Interpolator*>(interpolatorPtr); 167 animator->setInterpolator(interpolator); 168} 169 170static void setAllowRunningAsync(JNIEnv* env, jobject clazz, jlong animatorPtr, jboolean mayRunAsync) { 171 BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr); 172 animator->setAllowRunningAsync(mayRunAsync); 173} 174 175static void setListener(JNIEnv* env, jobject clazz, jlong animatorPtr, jobject finishListener) { 176 BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr); 177 animator->setListener(new AnimationListenerBridge(env, finishListener)); 178} 179 180static void start(JNIEnv* env, jobject clazz, jlong animatorPtr) { 181 BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr); 182 animator->start(); 183} 184 185static void end(JNIEnv* env, jobject clazz, jlong animatorPtr) { 186 BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr); 187 animator->cancel(); 188} 189 190// ---------------------------------------------------------------------------- 191// JNI Glue 192// ---------------------------------------------------------------------------- 193 194const char* const kClassPathName = "android/view/RenderNodeAnimator"; 195 196static const JNINativeMethod gMethods[] = { 197 { "nCreateAnimator", "(IF)J", (void*) createAnimator }, 198 { "nCreateCanvasPropertyFloatAnimator", "(JF)J", (void*) createCanvasPropertyFloatAnimator }, 199 { "nCreateCanvasPropertyPaintAnimator", "(JIF)J", (void*) createCanvasPropertyPaintAnimator }, 200 { "nCreateRevealAnimator", "(IIFF)J", (void*) createRevealAnimator }, 201 { "nSetStartValue", "(JF)V", (void*) setStartValue }, 202 { "nSetDuration", "(JJ)V", (void*) setDuration }, 203 { "nGetDuration", "(J)J", (void*) getDuration }, 204 { "nSetStartDelay", "(JJ)V", (void*) setStartDelay }, 205 { "nSetInterpolator", "(JJ)V", (void*) setInterpolator }, 206 { "nSetAllowRunningAsync", "(JZ)V", (void*) setAllowRunningAsync }, 207 { "nSetListener", "(JLandroid/view/RenderNodeAnimator;)V", (void*) setListener}, 208 { "nStart", "(J)V", (void*) start}, 209 { "nEnd", "(J)V", (void*) end }, 210}; 211 212int register_android_view_RenderNodeAnimator(JNIEnv* env) { 213 sLifecycleChecker.incStrong(0); 214 gRenderNodeAnimatorClassInfo.clazz = FindClassOrDie(env, kClassPathName); 215 gRenderNodeAnimatorClassInfo.clazz = MakeGlobalRefOrDie(env, 216 gRenderNodeAnimatorClassInfo.clazz); 217 218 gRenderNodeAnimatorClassInfo.callOnFinished = GetStaticMethodIDOrDie( 219 env, gRenderNodeAnimatorClassInfo.clazz, "callOnFinished", 220 "(Landroid/view/RenderNodeAnimator;)V"); 221 222 return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods)); 223} 224 225 226} // namespace android 227