FreeRDP/client/Android/android_jni_callback.c

228 lines
5.2 KiB
C

/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Android JNI Callback Helpers
*
* Copyright 2011-2013 Thincast Technologies GmbH, Author: Martin Fleisz
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include "android_jni_callback.h"
#include "android_freerdp_jni.h"
#include <freerdp/log.h>
#define TAG CLIENT_TAG("android.callback")
static JavaVM* jVM;
static jobject jLibFreeRDPObject;
static const char* jLibFreeRDPPath = JAVA_LIBFREERDP_CLASS;
static void jni_load_class(JNIEnv* env, const char* path, jobject* objptr)
{
jclass class;
jmethodID method;
jobject object;
WLog_DBG(TAG, "jni_load_class: %s", path);
class = (*env)->FindClass(env, path);
if (!class)
{
WLog_ERR(TAG, "jni_load_class: failed to find class %s", path);
goto finish;
}
method = (*env)->GetMethodID(env, class, "<init>", "()V");
if (!method)
{
WLog_ERR(TAG, "jni_load_class: failed to find class constructor of %s", path);
goto finish;
}
object = (*env)->NewObject(env, class, method);
if (!object)
{
WLog_ERR(TAG, "jni_load_class: failed create new object of %s", path);
goto finish;
}
(*objptr) = (*env)->NewGlobalRef(env, object);
finish:
while (0)
;
}
jint init_callback_environment(JavaVM* vm, JNIEnv* env)
{
jVM = vm;
jni_load_class(env, jLibFreeRDPPath, &jLibFreeRDPObject);
return JNI_VERSION_1_6;
}
/* attach current thread to jvm */
jboolean jni_attach_thread(JNIEnv** env)
{
if ((*jVM)->GetEnv(jVM, (void**)env, JNI_VERSION_1_4) != JNI_OK)
{
WLog_DBG(TAG, "android_java_callback: attaching current thread");
(*jVM)->AttachCurrentThread(jVM, env, NULL);
if ((*jVM)->GetEnv(jVM, (void**)env, JNI_VERSION_1_4) != JNI_OK)
{
WLog_ERR(TAG, "android_java_callback: failed to obtain current JNI environment");
}
return JNI_TRUE;
}
return JNI_FALSE;
}
/* attach current thread to JVM */
void jni_detach_thread()
{
(*jVM)->DetachCurrentThread(jVM);
}
/* callback with void result */
static void java_callback_void(jobject obj, const char* callback, const char* signature,
va_list args)
{
jclass jObjClass;
jmethodID jCallback;
jboolean attached;
JNIEnv* env;
WLog_DBG(TAG, "java_callback: %s (%s)", callback, signature);
attached = jni_attach_thread(&env);
jObjClass = (*env)->GetObjectClass(env, obj);
if (!jObjClass)
{
WLog_ERR(TAG, "android_java_callback: failed to get class reference");
goto finish;
}
jCallback = (*env)->GetStaticMethodID(env, jObjClass, callback, signature);
if (!jCallback)
{
WLog_ERR(TAG, "android_java_callback: failed to get method id");
goto finish;
}
(*env)->CallStaticVoidMethodV(env, jObjClass, jCallback, args);
finish:
if (attached == JNI_TRUE)
jni_detach_thread();
}
/* callback with bool result */
static jboolean java_callback_bool(jobject obj, const char* callback, const char* signature,
va_list args)
{
jclass jObjClass;
jmethodID jCallback;
jboolean attached;
jboolean res = JNI_FALSE;
JNIEnv* env;
WLog_DBG(TAG, "java_callback: %s (%s)", callback, signature);
attached = jni_attach_thread(&env);
jObjClass = (*env)->GetObjectClass(env, obj);
if (!jObjClass)
{
WLog_ERR(TAG, "android_java_callback: failed to get class reference");
goto finish;
}
jCallback = (*env)->GetStaticMethodID(env, jObjClass, callback, signature);
if (!jCallback)
{
WLog_ERR(TAG, "android_java_callback: failed to get method id");
goto finish;
}
res = (*env)->CallStaticBooleanMethodV(env, jObjClass, jCallback, args);
finish:
if (attached == JNI_TRUE)
jni_detach_thread();
return res;
}
/* callback with int result */
static jint java_callback_int(jobject obj, const char* callback, const char* signature,
va_list args)
{
jclass jObjClass;
jmethodID jCallback;
jboolean attached;
jint res = -1;
JNIEnv* env;
WLog_DBG(TAG, "java_callback: %s (%s)", callback, signature);
attached = jni_attach_thread(&env);
jObjClass = (*env)->GetObjectClass(env, obj);
if (!jObjClass)
{
WLog_ERR(TAG, "android_java_callback: failed to get class reference");
goto finish;
}
jCallback = (*env)->GetStaticMethodID(env, jObjClass, callback, signature);
if (!jCallback)
{
WLog_ERR(TAG, "android_java_callback: failed to get method id");
goto finish;
}
res = (*env)->CallStaticIntMethodV(env, jObjClass, jCallback, args);
finish:
if (attached == JNI_TRUE)
jni_detach_thread();
return res;
}
/* callback to freerdp class */
void freerdp_callback(const char* callback, const char* signature, ...)
{
va_list vl;
va_start(vl, signature);
java_callback_void(jLibFreeRDPObject, callback, signature, vl);
va_end(vl);
}
jboolean freerdp_callback_bool_result(const char* callback, const char* signature, ...)
{
va_list vl;
va_start(vl, signature);
jboolean res = java_callback_bool(jLibFreeRDPObject, callback, signature, vl);
va_end(vl);
return res;
}
jint freerdp_callback_int_result(const char* callback, const char* signature, ...)
{
va_list vl;
va_start(vl, signature);
jint res = java_callback_int(jLibFreeRDPObject, callback, signature, vl);
va_end(vl);
return res;
}