Greg Pomerantz: 1 app: add RegisterFragment method on *Window for Android 7 files changed, 140 insertions(+), 15 deletions(-)
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~eliasnaur/gio/patches/9107/mbox | git am -3Learn more about email & git
RegisterFragment creates an instance of a Java class and attempts to register it as a Fragment in the window's Context. Signed-off-by: Greg Pomerantz <gmp.gio@wow.st> --- app/app.go | 7 ---- app/app_android.go | 29 ++++++++++++++++ app/internal/window/GioView.java | 70 ++++++++++++++++++++++++++++++++++++++- app/internal/window/handle.go | 7 ---- app/internal/window/os_android.c | 13 ++++++++ app/internal/window/os_android.go | 26 +++++++++++++++ app/internal/window/os_android.h | 3 ++ 7 files changed, 140 insertions(+), 15 deletions(-) create mode 100644 app/app_android.go delete mode 100644 app/internal/window/handle.go diff --git a/app/app.go b/app/app.go index 9a18ec4..71bc57b 100644 --- a/app/app.go +++ b/app/app.go @@ -9,13 +9,6 @@ import ( "gioui.org/app/internal/window" ) -type Handle window.Handle - -// PlatformHandle returns the platform specific Handle. -func PlatformHandle() *Handle { - return (*Handle)(window.PlatformHandle) -} - // extraArgs contains extra arguments to append to // os.Args. The arguments are separated with |. // Useful for running programs on mobiles where the diff --git a/app/app_android.go b/app/app_android.go new file mode 100644 index 0000000..e83aa74 --- /dev/null +++ b/app/app_android.go @@ -0,0 +1,29 @@ +package app + +import ( + "errors" + + "gioui.org/app/internal/window" +) + +type Handle window.Handle + +// PlatformHandle returns the Android platform-specific Handle. +func PlatformHandle() *Handle { + return (*Handle)(window.PlatformHandle) +} + +// RegisterFragment constructs a Java instance of the specified class +// and attempts to register it as a Fragment in the Context in which +// the View was created. +// +// NOTE: This method must not be called from the Gio application's main +// event loop, as that would block the View's UI thread and result in a +// deadlock. +func (w *Window) RegisterFragment(del string) error { + d := w.driver.(window.AndroidDriver) + if d == nil { + return errors.New("RegisterFragment: no window driver found") + } + return d.RegisterFragment(del) +} diff --git a/app/internal/window/GioView.java b/app/internal/window/GioView.java index 82bc36f..d601269 100644 --- a/app/internal/window/GioView.java +++ b/app/internal/window/GioView.java @@ -2,12 +2,27 @@ package org.gioui; +import java.lang.Class; +import java.lang.ClassLoader; +import java.lang.reflect.Method; +import java.lang.IllegalAccessException; +import java.lang.InstantiationException; +import java.lang.ExceptionInInitializerError; +import java.lang.NoSuchMethodException; +import java.lang.NullPointerException; +import java.lang.SecurityException; +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import android.app.Fragment; +import android.app.FragmentManager; +import android.app.FragmentTransaction; import android.content.Context; import android.graphics.Rect; import android.os.Build; import android.os.Handler; -import android.util.AttributeSet; import android.text.Editable; +import android.util.AttributeSet; import android.view.Choreographer; import android.view.KeyCharacterMap; import android.view.KeyEvent; @@ -207,6 +222,59 @@ public class GioView extends SurfaceView implements Choreographer.FrameCallback return onBack(nhandle); } + public String registerFragment(String del) { + final Class cls; + final Fragment frag; + try { + cls = getContext().getClassLoader().loadClass(del); + frag = (Fragment)cls.newInstance(); + } + catch (ClassNotFoundException ignored) { + return "RegisterFragment: fragment class not found"; + } + catch (IllegalAccessException | InstantiationException | ExceptionInInitializerError ignored) { + return "RegisterFragment: cannot instantiate delegate object"; + } + catch (SecurityException ignored) { + return "RegisterFragment: security exception"; + } + catch (ClassCastException ignored) { + return "RegisterFragment: provided class does not extend Fragment"; + } + + final BlockingQueue<String> q = new LinkedBlockingQueue<String>(); + + handler.post(new Runnable() { + public void run() { + final Context ctx = getContext(); + if (ctx == null) { + q.add("RegisterFragment: GioView has null context"); + return; + } + final FragmentManager fm; + try { + final Method mth = ctx.getClass().getMethod("getFragmentManager"); + fm = (FragmentManager)mth.invoke(ctx); + } + catch (NoSuchMethodException | NullPointerException | InvocationTargetException | ClassCastException | IllegalAccessException ignored) { + q.add("RegisterFragment: Cannot get Fragment manager from View Context"); + return; + } + q.add(""); + FragmentTransaction ft = fm.beginTransaction(); + ft.add(frag, del); + ft.commitNow(); + } + }); + // NOTE: Because of the use of a BlockingQueue here, this method + // cannot be called while the main UI thread is blocked. + try { + return q.take(); + } catch (InterruptedException e) { + return "RegisterFragment: interrupted"; + } + } + static private native long onCreateView(GioView view); static private native void onDestroyView(long handle); static private native void onStartView(long handle); diff --git a/app/internal/window/handle.go b/app/internal/window/handle.go deleted file mode 100644 index 5d7b1a1..0000000 --- a/app/internal/window/handle.go @@ -1,7 +0,0 @@ -// +build !android - -package window - -var PlatformHandle *Handle - -type Handle struct{} diff --git a/app/internal/window/os_android.c b/app/internal/window/os_android.c index 5150ab6..435350d 100644 --- a/app/internal/window/os_android.c +++ b/app/internal/window/os_android.c @@ -166,3 +166,16 @@ void gio_jni_ReleaseByteArrayElements(JNIEnv *env, jbyteArray arr, jbyte *bytes) jsize gio_jni_GetArrayLength(JNIEnv *env, jbyteArray arr) { return (*env)->GetArrayLength(env, arr); } + +jstring gio_jni_RegisterFragment(JNIEnv *env, jobject view, jmethodID mid, char* del) { + jstring jdel = (*env)->NewStringUTF(env, del); + return (*env)->CallObjectMethod(env, view, mid, jdel); +} + +const char *gio_jni_GetStringUTFChars(JNIEnv *env, jstring string) { + return (*env)->GetStringUTFChars(env, string, NULL); +} + +void gio_jni_ReleaseStringUTFChars(JNIEnv *env, jstring string, const char *utf) { + (*env)->ReleaseStringUTFChars(env, string, utf); +} diff --git a/app/internal/window/os_android.go b/app/internal/window/os_android.go index 5cce88d..74d7482 100644 --- a/app/internal/window/os_android.go +++ b/app/internal/window/os_android.go @@ -54,6 +54,7 @@ type window struct { mhideTextInput C.jmethodID mpostFrameCallback C.jmethodID mpostFrameCallbackOnMainThread C.jmethodID + mRegisterFragment C.jmethodID } var dataDirChan = make(chan string, 1) @@ -119,6 +120,7 @@ func onCreateView(env *C.JNIEnv, class C.jclass, view C.jobject) C.jlong { mhideTextInput: jniGetMethodID(env, class, "hideTextInput", "()V"), mpostFrameCallback: jniGetMethodID(env, class, "postFrameCallback", "()V"), mpostFrameCallbackOnMainThread: jniGetMethodID(env, class, "postFrameCallbackOnMainThread", "()V"), + mRegisterFragment: jniGetMethodID(env, class, "registerFragment", "(Ljava/lang/String;)Ljava/lang/String;"), } wopts := <-mainWindow.out w.callbacks = wopts.window @@ -443,6 +445,30 @@ func (w *window) ShowTextInput(show bool) { }) } +type AndroidDriver interface { + RegisterFragment(string) error +} + +func (w *window) RegisterFragment(del string) error { + if w.view == 0 { + return errors.New("RegisterFragment: view is null") + } + ret := "" + runInJVM(func(env *C.JNIEnv) { + cdel := C.CString(del) + defer C.free(unsafe.Pointer(cdel)) + jret := C.gio_jni_RegisterFragment(env, w.view, w.mRegisterFragment, cdel) + utf := C.gio_jni_GetStringUTFChars(env, jret) + ret = C.GoString(utf) + C.gio_jni_ReleaseStringUTFChars(env, jret, utf) + }) + if ret == "" { + return nil + } else { + return errors.New(ret) + } +} + func Main() { } diff --git a/app/internal/window/os_android.h b/app/internal/window/os_android.h index 288d633..d17366c 100644 --- a/app/internal/window/os_android.h +++ b/app/internal/window/os_android.h @@ -17,3 +17,6 @@ __attribute__ ((visibility ("hidden"))) void gio_jni_CallVoidMethod_J(JNIEnv *en __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"))) jstring gio_jni_RegisterFragment(JNIEnv *env, jobject view, jmethodID mid, char* del); +__attribute__ ((visibility ("hidden"))) const char *gio_jni_GetStringUTFChars(JNIEnv *env, jstring string); +__attribute__ ((visibility ("hidden"))) void gio_jni_ReleaseStringUTFChars(JNIEnv *env, jstring string, const char *utf); -- 2.16.2