From aefc6f36256a2a67b111252d814883f4b4ed2442 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Mon, 20 Apr 2020 20:54:50 +0200 Subject: [PATCH] app/internal/window: [Android] use correct JNI Call variant for registerFragment While we're here, - replace the registerFragment trampoline with a general variadic CallVoidMethod trampoline. - Use UTF-16 for passing strings to Java. Java's modified UTF-8 encoding differ from Go's in corner cases. Signed-off-by: Elias Naur --- app/internal/window/os_android.c | 9 ++++---- app/internal/window/os_android.go | 35 ++++++++++++++++++++++++------- app/internal/window/os_android.h | 4 ++-- 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/app/internal/window/os_android.c b/app/internal/window/os_android.c index 8a153d48..3bdf47ab 100644 --- a/app/internal/window/os_android.c +++ b/app/internal/window/os_android.c @@ -147,8 +147,8 @@ jint gio_jni_CallIntMethod(JNIEnv *env, jobject obj, jmethodID methodID) { return (*env)->CallIntMethod(env, obj, methodID); } -void gio_jni_CallVoidMethod(JNIEnv *env, jobject obj, jmethodID methodID) { - (*env)->CallVoidMethod(env, obj, methodID); +void gio_jni_CallVoidMethod(JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args) { + (*env)->CallVoidMethodA(env, obj, methodID, args); } jbyte *gio_jni_GetByteArrayElements(JNIEnv *env, jbyteArray arr) { @@ -163,7 +163,6 @@ jsize gio_jni_GetArrayLength(JNIEnv *env, jbyteArray arr) { return (*env)->GetArrayLength(env, arr); } -void gio_jni_RegisterFragment(JNIEnv *env, jobject view, jmethodID mid, char* del) { - jstring jdel = (*env)->NewStringUTF(env, del); - (*env)->CallObjectMethod(env, view, mid, jdel); +jstring gio_jni_NewString(JNIEnv *env, const jchar *unicodeChars, jsize len) { + return (*env)->NewString(env, unicodeChars, len); } diff --git a/app/internal/window/os_android.go b/app/internal/window/os_android.go index def55c35..ae47a6ed 100644 --- a/app/internal/window/os_android.go +++ b/app/internal/window/os_android.go @@ -23,6 +23,7 @@ import ( "runtime/debug" "sync" "time" + "unicode/utf16" "unsafe" "gioui.org/f32" @@ -57,6 +58,8 @@ type window struct { mRegisterFragment C.jmethodID } +type jvalue uint64 // The largest JNI type fits in 64 bits. + var dataDirChan = make(chan string, 1) var theJVM *C.JavaVM @@ -212,7 +215,7 @@ func onFrameCallback(env *C.JNIEnv, class C.jclass, view C.jlong, nanos C.jlong) w.mu.Unlock() if anim { runInJVM(func(env *C.JNIEnv) { - C.gio_jni_CallVoidMethod(env, w.view, w.mpostFrameCallback) + callVoidMethod(env, w.view, w.mpostFrameCallback) }) w.draw(false) } @@ -306,7 +309,7 @@ func (w *window) SetAnimating(anim bool) { w.mu.Unlock() if anim { runInJVM(func(env *C.JNIEnv) { - C.gio_jni_CallVoidMethod(env, w.view, w.mpostFrameCallbackOnMainThread) + callVoidMethod(env, w.view, w.mpostFrameCallbackOnMainThread) }) } } @@ -448,21 +451,39 @@ func (w *window) ShowTextInput(show bool) { } runInJVM(func(env *C.JNIEnv) { if show { - C.gio_jni_CallVoidMethod(env, w.view, w.mshowTextInput) + callVoidMethod(env, w.view, w.mshowTextInput) } else { - C.gio_jni_CallVoidMethod(env, w.view, w.mhideTextInput) + callVoidMethod(env, w.view, w.mhideTextInput) } }) } +func javaString(env *C.JNIEnv, str string) C.jstring { + if str == "" { + return 0 + } + utf16Chars := utf16.Encode([]rune(str)) + return C.gio_jni_NewString(env, (*C.jchar)(unsafe.Pointer(&utf16Chars[0])), C.int(len(utf16Chars))) +} + func (w *window) RegisterFragment(del string) { runInJVM(func(env *C.JNIEnv) { - cdel := C.CString(del) - defer C.free(unsafe.Pointer(cdel)) - C.gio_jni_RegisterFragment(env, w.view, w.mRegisterFragment, cdel) + jstr := javaString(env, del) + callVoidMethod(env, w.view, w.mRegisterFragment, jvalue(jstr)) }) } +func varArgs(args []jvalue) *C.jvalue { + if len(args) == 0 { + return nil + } + return (*C.jvalue)(unsafe.Pointer(&args[0])) +} + +func callVoidMethod(env *C.JNIEnv, obj C.jobject, method C.jmethodID, args ...jvalue) { + C.gio_jni_CallVoidMethod(env, obj, method, varArgs(args)) +} + func Main() { } diff --git a/app/internal/window/os_android.h b/app/internal/window/os_android.h index 738f5272..5b5b1217 100644 --- a/app/internal/window/os_android.h +++ b/app/internal/window/os_android.h @@ -12,8 +12,8 @@ __attribute__ ((visibility ("hidden"))) jmethodID gio_jni_GetMethodID(JNIEnv *en __attribute__ ((visibility ("hidden"))) jint gio_jni_CallStaticIntMethodII(JNIEnv *env, jclass clazz, jmethodID methodID, jint a1, jint a2); __attribute__ ((visibility ("hidden"))) jfloat gio_jni_CallFloatMethod(JNIEnv *env, jobject obj, jmethodID methodID); __attribute__ ((visibility ("hidden"))) jint gio_jni_CallIntMethod(JNIEnv *env, jobject obj, jmethodID methodID); -__attribute__ ((visibility ("hidden"))) void gio_jni_CallVoidMethod(JNIEnv *env, jobject obj, jmethodID methodID); +__attribute__ ((visibility ("hidden"))) void gio_jni_CallVoidMethod(JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); __attribute__ ((visibility ("hidden"))) jbyte *gio_jni_GetByteArrayElements(JNIEnv *env, jbyteArray arr); __attribute__ ((visibility ("hidden"))) void gio_jni_ReleaseByteArrayElements(JNIEnv *env, jbyteArray arr, jbyte *bytes); __attribute__ ((visibility ("hidden"))) jsize gio_jni_GetArrayLength(JNIEnv *env, jbyteArray arr); -__attribute__ ((visibility ("hidden"))) void gio_jni_RegisterFragment(JNIEnv *env, jobject view, jmethodID mid, char* del); +__attribute__ ((visibility ("hidden"))) jstring gio_jni_NewString(JNIEnv *env, const jchar *unicodeChars, jsize len);