Greg Pomerantz: 1 app: add RegisterFragment method on *Window for Android 8 files changed, 100 insertions(+), 16 deletions(-)
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~eliasnaur/gio-patches/patches/9156/mbox | git am -3Learn more about email & git
RegisterFragment creates an instance of a Java class and registers 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 | 30 +++++++++++++++++++++++++++ app/internal/window/GioView.java | 43 +++++++++++++++++++++++++++++++++++++-- app/internal/window/handle.go | 7 ------- app/internal/window/os_android.c | 5 +++++ app/internal/window/os_android.go | 10 +++++++++ app/internal/window/os_android.h | 1 + app/window.go | 13 ++++++++++++ 8 files changed, 100 insertions(+), 16 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..13a004a --- /dev/null +++ b/app/app_android.go @@ -0,0 +1,30 @@ +package app + +import ( + "gioui.org/app/internal/window" +) + +type Handle window.Handle + +// PlatformHandle returns the Android platform-specific Handle. +func PlatformHandle() *Handle { + return (*Handle)(window.PlatformHandle) +} + +// androidDriver is an interface that allows the Window's run method +// to call the RegisterFragment method of the Android window driver. +type androidDriver interface { + RegisterFragment(string) +} + +// RegisterFragment constructs a Java instance of the specified class +// and registers it as a Fragment in the Context in which the View was +// created. +func (w *Window) RegisterFragment(del string) { + go func() { + w.driverFuncs <- func() { + d := w.driver.(androidDriver) + d.RegisterFragment(del) + } + }() +} diff --git a/app/internal/window/GioView.java b/app/internal/window/GioView.java index 82bc36f..2217365 100644 --- a/app/internal/window/GioView.java +++ b/app/internal/window/GioView.java @@ -2,12 +2,21 @@ package org.gioui; +import java.lang.Class; +import java.lang.IllegalAccessException; +import java.lang.InstantiationException; +import java.lang.ExceptionInInitializerError; +import java.lang.SecurityException; +import android.app.Activity; +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; @@ -57,11 +66,12 @@ public class GioView extends SurfaceView implements Choreographer.FrameCallback public GioView(Context context, AttributeSet attrs) { super(context, attrs); + + handler = new Handler(); // Late initialization of the Go runtime to wait for a valid context. initialize(context.getApplicationContext()); nhandle = onCreateView(this); - handler = new Handler(); imm = (InputMethodManager)context.getSystemService(Context.INPUT_METHOD_SERVICE); setFocusable(true); setFocusableInTouchMode(true); @@ -207,6 +217,35 @@ public class GioView extends SurfaceView implements Choreographer.FrameCallback return onBack(nhandle); } + public void registerFragment(String del) { + final Class cls; + try { + cls = getContext().getClassLoader().loadClass(del); + } catch (ClassNotFoundException e) { + throw new RuntimeException("RegisterFragment: fragment class not found: " + e.getMessage()); + } + + handler.post(new Runnable() { + public void run() { + final Fragment frag; + try { + frag = (Fragment)cls.newInstance(); + } catch (IllegalAccessException | InstantiationException | ExceptionInInitializerError | SecurityException | ClassCastException e) { + throw new RuntimeException("RegisterFragment: error instantiating fragment: " + e.getMessage()); + } + final FragmentManager fm; + try { + fm = (FragmentManager)((Activity)(getContext())).getFragmentManager();
Redundant cast and parens: fm = ((Activity)getContext()).getFragmentManager();
+ } catch (ClassCastException e) { + throw new RuntimeException("RegisterFragment: cannot get fragment manager from View Context: " + e.getMessage()); + } + FragmentTransaction ft = fm.beginTransaction(); + ft.add(frag, del); + ft.commitNow(); + } + }); + } + 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..3dba313 100644 --- a/app/internal/window/os_android.c +++ b/app/internal/window/os_android.c @@ -166,3 +166,8 @@ void gio_jni_ReleaseByteArrayElements(JNIEnv *env, jbyteArray arr, jbyte *bytes) 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); +} diff --git a/app/internal/window/os_android.go b/app/internal/window/os_android.go index 5cce88d..3a7d52c 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;)V"), } wopts := <-mainWindow.out w.callbacks = wopts.window @@ -443,6 +445,14 @@ func (w *window) ShowTextInput(show bool) { }) } +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) + }) +} + func Main() { } diff --git a/app/internal/window/os_android.h b/app/internal/window/os_android.h index 288d633..e19d28b 100644 --- a/app/internal/window/os_android.h +++ b/app/internal/window/os_android.h @@ -17,3 +17,4 @@ __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"))) void gio_jni_RegisterFragment(JNIEnv *env, jobject view, jmethodID mid, char* del); diff --git a/app/window.go b/app/window.go index 8b41d21..c10465d 100644 --- a/app/window.go +++ b/app/window.go @@ -29,6 +29,10 @@ type Window struct { driver window.Driver gpu *gpu.GPU + // driverFuncs is a channel of functions to run when + // the Window has a valid driver. + driverFuncs chan func() + out chan event.Event in chan event.Event ack chan struct{} @@ -95,6 +99,7 @@ func NewWindow(options ...Option) *Window { invalidates: make(chan struct{}, 1), frames: make(chan *op.Ops), frameAck: make(chan struct{}), + driverFuncs: make(chan func()), } w.callbacks.w = w go w.run(opts) @@ -226,6 +231,7 @@ func (w *Window) run(opts *window.Options) { w.out <- system.DestroyEvent{Err: err} return } + var driverFuncs chan func() for {
Move this into the for loop. Simpler and the setting of driverFuncs closer to its definition:
var timer <-chan time.Time
var driverFuncs chan func() if w.driver != nil {Gregory PomerantzDo you mind if I say var driverFuncs chan func() = nil to make clear that this resets to nil each loop unless w.driver != nil?driverFuncs = w.driverFuncs }
if w.delayedDraw != nil { @@ -238,6 +244,8 @@ func (w *Window) run(opts *window.Options) { case <-w.invalidates: w.setNextFrame(time.Time{}) w.updateAnimation() + case f := <-driverFuncs: + f() case e := <-w.in: switch e2 := e.(type) { case system.StageEvent: @@ -316,6 +324,11 @@ func (w *Window) run(opts *window.Options) { w.waitAck() case driverEvent: w.driver = e2.driver + if w.driver == nil { + driverFuncs = nil + } else { + driverFuncs = w.driverFuncs + } case system.DestroyEvent: w.destroyGPU() w.out <- e2 -- 2.16.2
View this thread in the archivesAlmost there! On Tue Nov 26, 2019 at 9:19 AM Greg Pomerantz wrote: