Greg Pomerantz: 1 app: add Android-specific Run method on *Window 8 files changed, 98 insertions(+), 23 deletions(-)
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~eliasnaur/gio/patches/9080/mbox | git am -3Learn more about email & git
Run runs a function on the main UI thread that requires access to an Android activity. A nil activity is returned if none is available. Signed-off-by: Greg Pomerantz <gmp.gio@wow.st> --- app/app.go | 7 ------- app/app_android.go | 35 +++++++++++++++++++++++++++++++++++ app/internal/window/GioActivity.java | 2 +- app/internal/window/GioView.java | 28 +++++++++++++++++++++------- app/internal/window/handle.go | 7 ------- app/internal/window/os_android.c | 11 ++++++++++- app/internal/window/os_android.go | 27 +++++++++++++++++++++++++++ app/internal/window/os_android.h | 4 ++++ 8 files changed, 98 insertions(+), 23 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..b41bb43 --- /dev/null +++ b/app/app_android.go @@ -0,0 +1,35 @@ +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) +} + +// JNIEnv is a struct wrapping a pointer to a JNI environment with an +// underlying type of *C.JNIEnv. +type JNIEnv struct { + JNIEnv uintptr +} + +// Activity is a struct that wraps a pointer to an Android Activity with an +// underlying type of C.jobject. +type Activity struct { + Activity uintptr +} + +// Run runs a function that needs access to the Android Activity for the +// window. The function is run on the UI thread and should not block. The +// function must be prepared to deal with a nil activity if none is +// available. Run returns immediately and does not wait for the completion +// of f. +func (w *Window) Run(f func(env JNIEnv, activity Activity)) { + window.Run(w.driver, func(e, a uintptr) { + f(JNIEnv{e}, Activity{a}) + }) +} diff --git a/app/internal/window/GioActivity.java b/app/internal/window/GioActivity.java index 2813d80..1a91f81 100644 --- a/app/internal/window/GioActivity.java +++ b/app/internal/window/GioActivity.java @@ -33,7 +33,7 @@ public class GioActivity extends Activity { @Override public void onStart() { super.onStart(); - view.start(); + view.start(this); } @Override public void onStop() { diff --git a/app/internal/window/GioView.java b/app/internal/window/GioView.java index 82bc36f..535ad58 100644 --- a/app/internal/window/GioView.java +++ b/app/internal/window/GioView.java @@ -2,6 +2,7 @@ package org.gioui; +import android.app.Activity; import android.content.Context; import android.graphics.Rect; import android.os.Build; @@ -32,6 +33,7 @@ public class GioView extends SurfaceView implements Choreographer.FrameCallback private final InputMethodManager imm; private final Handler handler; private long nhandle; + private Activity activity; private static synchronized void initialize(Context appCtx) { synchronized (initLock) { @@ -51,18 +53,18 @@ public class GioView extends SurfaceView implements Choreographer.FrameCallback } } - public GioView(Context context) { - this(context, null); + public GioView(Activity activity) { + this(activity, null); } - public GioView(Context context, AttributeSet attrs) { - super(context, attrs); + public GioView(Activity activity, AttributeSet attrs) { + super(activity, attrs); // Late initialization of the Go runtime to wait for a valid context. - initialize(context.getApplicationContext()); + initialize(activity.getApplicationContext()); nhandle = onCreateView(this); handler = new Handler(); - imm = (InputMethodManager)context.getSystemService(Context.INPUT_METHOD_SERVICE); + imm = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE); setFocusable(true); setFocusableInTouchMode(true); setOnFocusChangeListener(new View.OnFocusChangeListener() { @@ -181,15 +183,18 @@ public class GioView extends SurfaceView implements Choreographer.FrameCallback return getResources().getConfiguration().fontScale; } - void start() { + void start(Activity act) { + this.activity = act; onStartView(nhandle); } void stop() { + this.activity = null; onStopView(nhandle); } void destroy() { + this.activity = null; getHolder().removeCallback(callbacks); onDestroyView(nhandle); nhandle = 0; @@ -207,6 +212,14 @@ public class GioView extends SurfaceView implements Choreographer.FrameCallback return onBack(nhandle); } + public void Run(long funcPtr) { + handler.post(new Runnable() { + public void run() { + runCallback(activity, funcPtr); + } + }); + } + static private native long onCreateView(GioView view); static private native void onDestroyView(long handle); static private native void onStartView(long handle); @@ -222,6 +235,7 @@ public class GioView extends SurfaceView implements Choreographer.FrameCallback static private native boolean onBack(long handle); static private native void onFocusChange(long handle, boolean focus); static private native void runGoMain(byte[] dataDir, Context context); + static private native void runCallback(Activity activity, long funcPtr); private static class InputConnection extends BaseInputConnection { private final Editable editable; 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..b20ebea 100644 --- a/app/internal/window/os_android.c +++ b/app/internal/window/os_android.c @@ -94,7 +94,12 @@ JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { .name = "onFocusChange", .signature = "(JZ)V", .fnPtr = onFocusChange - } + }, + { + .name = "runCallback", + .signature = "(Landroid/app/Activity;J)V", + .fnPtr = runCallback + }, }; if ((*env)->RegisterNatives(env, viewClass, methods, sizeof(methods)/sizeof(methods[0])) != 0) { return -1; @@ -166,3 +171,7 @@ 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_CallGioViewRun(JNIEnv *env, jobject view, jmethodID mid, runcb_t f) { + (*env)->CallVoidMethod(env, view, mid, (jlong)f); +} diff --git a/app/internal/window/os_android.go b/app/internal/window/os_android.go index 5cce88d..693c3f3 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 + mRun C.jmethodID } var dataDirChan = make(chan string, 1) @@ -99,6 +100,31 @@ func runGoMain(env *C.JNIEnv, class C.jclass, jdataDir C.jbyteArray, context C.j runMain() } +func Run(d Driver, f func(a, b uintptr)) { + if d == nil { + go f(0, 0) + return + } + + // app/Window.Driver will always be a *window on Android, so this type- + // assertion is safe as long as Driver is not a nil interface. + w := d.(*window) + + if w == nil { + go f(0, 0) + return + } + runInJVM(func(env *C.JNIEnv) { + C.gio_jni_CallGioViewRun(env, w.view, w.mRun, (*[0]byte)(unsafe.Pointer(&f))) + }) +} + +//export runCallback +func runCallback(env *C.JNIEnv, class C.jclass, activity C.jobject, funcPtr C.runcb_t) { + f := (*func(a, b uintptr))(unsafe.Pointer(funcPtr)) + (*f)(uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(activity))) +} + func GetDataDir() string { return <-dataDirChan } @@ -119,6 +145,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"), + mRun: jniGetMethodID(env, class, "Run", "(J)V"), } wopts := <-mainWindow.out w.callbacks = wopts.window diff --git a/app/internal/window/os_android.h b/app/internal/window/os_android.h index 288d633..a31ec4b 100644 --- a/app/internal/window/os_android.h +++ b/app/internal/window/os_android.h @@ -17,3 +17,7 @@ __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); + +typedef void (*runcb_t)(JNIEnv *env, jobject activity); + +void gio_jni_CallGioViewRun(JNIEnv *env, jobject view, jmethodID mid, runcb_t f); -- 2.16.2