diff --git a/app/internal/window/Gio.java b/app/internal/window/Gio.java index 7bdf3b06..db57bff5 100644 --- a/app/internal/window/Gio.java +++ b/app/internal/window/Gio.java @@ -2,8 +2,6 @@ package org.gioui; -import android.content.ClipboardManager; -import android.content.ClipData; import android.content.Context; import java.io.UnsupportedEncodingException; @@ -37,19 +35,5 @@ public final class Gio { } } - private static void writeClipboard(Context ctx, String s) { - ClipboardManager m = (ClipboardManager)ctx.getSystemService(Context.CLIPBOARD_SERVICE); - m.setPrimaryClip(ClipData.newPlainText(null, s)); - } - - private static String readClipboard(Context ctx) { - ClipboardManager m = (ClipboardManager)ctx.getSystemService(Context.CLIPBOARD_SERVICE); - ClipData c = m.getPrimaryClip(); - if (c == null || c.getItemCount() < 1) { - return null; - } - return c.getItemAt(0).coerceToText(ctx).toString(); - } - static private native void runGoMain(byte[] dataDir, Context context); } diff --git a/app/internal/window/GioActivity.java b/app/internal/window/GioActivity.java index 2813d80e..260d4b69 100644 --- a/app/internal/window/GioActivity.java +++ b/app/internal/window/GioActivity.java @@ -10,7 +10,7 @@ import android.view.View; import android.view.Window; import android.view.WindowManager; -public class GioActivity extends Activity { +public final class GioActivity extends Activity { private GioView view; @Override public void onCreate(Bundle state) { diff --git a/app/internal/window/GioView.java b/app/internal/window/GioView.java index 300e58f7..6c2f2184 100644 --- a/app/internal/window/GioView.java +++ b/app/internal/window/GioView.java @@ -11,6 +11,8 @@ import android.app.Activity; import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentTransaction; +import android.content.ClipboardManager; +import android.content.ClipData; import android.content.Context; import android.graphics.Rect; import android.os.Build; @@ -33,7 +35,7 @@ import android.view.inputmethod.EditorInfo; import java.io.UnsupportedEncodingException; -public class GioView extends SurfaceView implements Choreographer.FrameCallback { +public final class GioView extends SurfaceView implements Choreographer.FrameCallback { private final static Object initLock = new Object(); private static boolean jniLoaded; @@ -199,7 +201,15 @@ public class GioView extends SurfaceView implements Choreographer.FrameCallback return onBack(nhandle); } - public void registerFragment(String del) { + protected void wakeupMainThread() { + handler.post(new Runnable() { + @Override public void run() { + scheduleMainFuncs(); + } + }); + } + + protected void registerFragment(String del) { final Class cls; try { cls = getContext().getClassLoader().loadClass(del); @@ -228,6 +238,20 @@ public class GioView extends SurfaceView implements Choreographer.FrameCallback }); } + protected void writeClipboard(String s) { + ClipboardManager m = (ClipboardManager)getContext().getSystemService(Context.CLIPBOARD_SERVICE); + m.setPrimaryClip(ClipData.newPlainText(null, s)); + } + + protected String readClipboard() { + ClipboardManager m = (ClipboardManager)getContext().getSystemService(Context.CLIPBOARD_SERVICE); + ClipData c = m.getPrimaryClip(); + if (c == null || c.getItemCount() < 1) { + return null; + } + return c.getItemAt(0).coerceToText(getContext()).toString(); + } + static private native long onCreateView(GioView view); static private native void onDestroyView(long handle); static private native void onStartView(long handle); @@ -242,6 +266,7 @@ public class GioView extends SurfaceView implements Choreographer.FrameCallback static private native void onFrameCallback(long handle, long nanos); static private native boolean onBack(long handle); static private native void onFocusChange(long handle, boolean focus); + static private native void scheduleMainFuncs(); private static class InputConnection extends BaseInputConnection { private final Editable editable; diff --git a/app/internal/window/os_android.go b/app/internal/window/os_android.go index 30f06f67..b5aa687e 100644 --- a/app/internal/window/os_android.go +++ b/app/internal/window/os_android.go @@ -74,6 +74,7 @@ type window struct { win *C.ANativeWindow animating bool + // Cached Java methods. mgetDensity C.jmethodID mgetFontScale C.jmethodID mshowTextInput C.jmethodID @@ -81,6 +82,9 @@ type window struct { mpostFrameCallback C.jmethodID mpostFrameCallbackOnMainThread C.jmethodID mRegisterFragment C.jmethodID + mwakeupMainThread C.jmethodID + mwriteClipboard C.jmethodID + mreadClipboard C.jmethodID } type jvalue uint64 // The largest JNI type fits in 64 bits. @@ -96,18 +100,14 @@ var android struct { // The global Android App context. appCtx C.jobject - // The Gio class reference. - gioCls C.jclass - - // Cached Java methods. - writeClipboard C.jmethodID - readClipboard C.jmethodID } var views = make(map[C.jlong]*window) var mainWindow = newWindowRendezvous() +var mainFuncs = make(chan func(env *C.JNIEnv), 1) + func getMethodID(env *C.JNIEnv, class C.jclass, method, sig string) C.jmethodID { m := C.CString(method) defer C.free(unsafe.Pointer(m)) @@ -153,10 +153,7 @@ func initJVM(env *C.JNIEnv, gio C.jclass, ctx C.jobject) { if res := C.gio_jni_GetJavaVM(env, &android.jvm); res != 0 { panic("gio: GetJavaVM failed") } - android.writeClipboard = getStaticMethodID(env, gio, "writeClipboard", "(Landroid/content/Context;Ljava/lang/String;)V") - android.readClipboard = getStaticMethodID(env, gio, "readClipboard", "(Landroid/content/Context;)Ljava/lang/String;") android.appCtx = C.gio_jni_NewGlobalRef(env, ctx) - android.gioCls = C.jclass(C.gio_jni_NewGlobalRef(env, C.jobject(gio))) } func JavaVM() uintptr { @@ -192,6 +189,9 @@ func Java_org_gioui_GioView_onCreateView(env *C.JNIEnv, class C.jclass, view C.j mpostFrameCallback: getMethodID(env, class, "postFrameCallback", "()V"), mpostFrameCallbackOnMainThread: getMethodID(env, class, "postFrameCallbackOnMainThread", "()V"), mRegisterFragment: getMethodID(env, class, "registerFragment", "(Ljava/lang/String;)V"), + mwakeupMainThread: getMethodID(env, class, "wakeupMainThread", "()V"), + mwriteClipboard: getMethodID(env, class, "writeClipboard", "(Ljava/lang/String;)V"), + mreadClipboard: getMethodID(env, class, "readClipboard", "()Ljava/lang/String;"), } wopts := <-mainWindow.out w.callbacks = wopts.window @@ -619,33 +619,40 @@ func NewWindow(window Callbacks, opts *Options) error { return <-mainWindow.errs } -func WriteClipboard(s string) error { - var jerr error - jvm := javaVM() - if jvm == nil { - return errors.New("clipboard: the JVM is not yet available") - } - runInJVM(jvm, func(env *C.JNIEnv) { +func (w *window) WriteClipboard(s string) { + w.runOnMain(func(env *C.JNIEnv) { jstr := javaString(env, s) - jerr = callStaticVoidMethod(env, android.gioCls, android.writeClipboard, jvalue(android.appCtx), jvalue(jstr)) + callVoidMethod(env, w.view, w.mwriteClipboard, jvalue(jstr)) }) - return jerr } -func ReadClipboard() (string, error) { - var clipboard string - var jerr error - jvm := javaVM() - if jvm == nil { - return "", errors.New("clipboard: the JVM is not yet available") - } - runInJVM(jvm, func(env *C.JNIEnv) { - c, err := callStaticObjectMethod(env, android.gioCls, android.readClipboard, jvalue(android.appCtx)) +func (w *window) ReadClipboard() { + w.runOnMain(func(env *C.JNIEnv) { + c, err := callObjectMethod(env, w.view, w.mreadClipboard) if err != nil { - jerr = err return } - clipboard = goString(env, C.jstring(c)) + content := goString(env, C.jstring(c)) + w.callbacks.Event(system.ClipboardEvent{Text: content}) }) - return clipboard, jerr +} + +// runOnMain runs a function on the Java main thread. +func (w *window) runOnMain(f func(env *C.JNIEnv)) { + mainFuncs <- f + runInJVM(javaVM(), func(env *C.JNIEnv) { + callVoidMethod(env, w.view, w.mwakeupMainThread) + }) +} + +//export Java_org_gioui_GioView_scheduleMainFuncs +func Java_org_gioui_GioView_scheduleMainFuncs(env *C.JNIEnv, this C.jobject) { + for { + select { + case f := <-mainFuncs: + f(env) + default: + return + } + } }