diff --git a/app/app_android.go b/app/app_android.go index e45eb3e7..cf6e9b7f 100644 --- a/app/app_android.go +++ b/app/app_android.go @@ -6,6 +6,8 @@ import ( "gioui.org/app/internal/window" ) +type ViewEvent = window.ViewEvent + // JavaVM returns the global JNI JavaVM. func JavaVM() uintptr { return window.JavaVM() @@ -16,42 +18,3 @@ func JavaVM() uintptr { func AppContext() uintptr { return window.AppContext() } - -// Do invokes the function with a JNI jobject handle to the underlying -// Android View. The function is invoked on the main thread, and the -// handle is invalidated after the function returns. -// -// Note: Do may deadlock if called from the same goroutine that receives from -// Events. -func (w *Window) Do(f func(view uintptr)) { - type androidDriver interface { - Do(f func(view uintptr)) bool - } - success := make(chan bool) - for { - driver := make(chan androidDriver) - // two-stage process: first wait for a valid driver... - go func() { - alive := w.driverDo(func() { - driver <- w.driver.(androidDriver) - }) - if !alive { - driver <- nil - } - }() - d := <-driver - if d == nil { - // Window is dead. - break - } - // .. then run the function on the main thread using the - // driver. The driver Do method returns false if the - // view was invalidated while switching to the main thread. - window.RunOnMain(func() { - success <- d.Do(f) - }) - if <-success { - break - } - } -} diff --git a/app/internal/window/os_android.go b/app/internal/window/os_android.go index 3458b261..dac0bf3f 100644 --- a/app/internal/window/os_android.go +++ b/app/internal/window/os_android.go @@ -82,6 +82,16 @@ type window struct { mpostFrameCallback C.jmethodID } +// ViewEvent is sent whenever the Window's underlying Android view +// changes. +type ViewEvent struct { + // View is a JNI global reference to the android.view.View + // instance backing the Window. The reference is valid until + // the next ViewEvent is received. + // A zero View means that there is currently no view attached. + View uintptr +} + type jvalue uint64 // The largest JNI type fits in 64 bits. var dataDirChan = make(chan string, 1) @@ -200,12 +210,14 @@ func Java_org_gioui_GioView_onCreateView(env *C.JNIEnv, class C.jclass, view C.j views[handle] = w w.loadConfig(env, class) w.setStage(system.StagePaused) + w.callbacks.Event(ViewEvent{View: uintptr(view)}) return handle } //export Java_org_gioui_GioView_onDestroyView func Java_org_gioui_GioView_onDestroyView(env *C.JNIEnv, class C.jclass, handle C.jlong) { w := views[handle] + w.callbacks.Event(ViewEvent{View: 0}) w.callbacks.SetDriver(nil) delete(views, handle) C.gio_jni_DeleteGlobalRef(env, w.view) @@ -532,23 +544,6 @@ func javaString(env *C.JNIEnv, str string) C.jstring { return C.gio_jni_NewString(env, (*C.jchar)(unsafe.Pointer(&utf16Chars[0])), C.int(len(utf16Chars))) } -// Do invokes the function with a global JNI handle to the view. If -// the view is destroyed, Do returns false and does not invoke the -// function. -// -// NOTE: Do must be invoked on the Android main thread. -func (w *window) Do(f func(view uintptr)) bool { - if w.view == 0 { - return false - } - runInJVM(javaVM(), func(env *C.JNIEnv) { - view := C.gio_jni_NewGlobalRef(env, w.view) - defer C.gio_jni_DeleteGlobalRef(env, view) - f(uintptr(view)) - }) - return true -} - func varArgs(args []jvalue) *C.jvalue { if len(args) == 0 { return nil @@ -653,14 +648,6 @@ func (w *window) ReadClipboard() { // Close the window. Not implemented for Android. func (w *window) Close() {} -// RunOnMain is the exported version of runOnMain without a JNI -// environement. -func RunOnMain(f func()) { - runOnMain(func(_ *C.JNIEnv) { - f() - }) -} - // runOnMain runs a function on the Java main thread. func runOnMain(f func(env *C.JNIEnv)) { go func() { @@ -682,3 +669,5 @@ func Java_org_gioui_Gio_scheduleMainFuncs(env *C.JNIEnv, cls C.jclass) { } } } + +func (_ ViewEvent) ImplementsEvent() {}