231 lines
5.3 KiB
C
231 lines
5.3 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;
|
|
}
|