diff --git a/internal/driver/mobile/app/GoNativeActivity.java b/internal/driver/mobile/app/GoNativeActivity.java index 866f3246bd..06f6442533 100644 --- a/internal/driver/mobile/app/GoNativeActivity.java +++ b/internal/driver/mobile/app/GoNativeActivity.java @@ -43,7 +43,6 @@ public class GoNativeActivity extends NativeActivity { private native void insetsChanged(int top, int bottom, int left, int right); private native void keyboardTyped(String str); private native void keyboardDelete(); - private native void backPressed(); private native void setDarkMode(boolean dark); private EditText mTextEdit; @@ -314,21 +313,6 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { filePickerReturned(uri.toString()); } - @Override - public void onBackPressed() { - // skip the default behaviour - we can call finishActivity if we want to go back - backPressed(); - } - - public void finishActivity() { - runOnUiThread(new Runnable() { - @Override - public void run() { - GoNativeActivity.super.onBackPressed(); - } - }); - } - @Override public void onConfigurationChanged(Configuration config) { super.onConfigurationChanged(config); diff --git a/internal/driver/mobile/app/android.c b/internal/driver/mobile/app/android.c index 0d73683f4b..a0c5d2efba 100644 --- a/internal/driver/mobile/app/android.c +++ b/internal/driver/mobile/app/android.c @@ -66,6 +66,23 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) { static int main_running = 0; +void set_global(ANativeActivity *activity){ + JNIEnv* env = activity->env; + if (current_class != NULL){ + (*env)->DeleteGlobalRef(activity->env, current_class); + } + // Note that activity->clazz is mis-named. + current_class = (*env)->GetObjectClass(env, activity->clazz); + current_class = (*env)->NewGlobalRef(env, current_class); + key_rune_method = find_static_method(env, current_class, "getRune", "(III)I"); + show_keyboard_method = find_static_method(env, current_class, "showKeyboard", "(I)V"); + hide_keyboard_method = find_static_method(env, current_class, "hideKeyboard", "()V"); + show_file_open_method = find_static_method(env, current_class, "showFileOpen", "(Ljava/lang/String;)V"); + show_file_save_method = find_static_method(env, current_class, "showFileSave", "(Ljava/lang/String;Ljava/lang/String;)V"); + finish_method = find_method(env, current_class, "finish", "()V"); + setCurrentContext(activity->vm, (*env)->NewGlobalRef(env, activity->clazz)); +} + // Entry point from our subclassed NativeActivity. // // By here, the Go runtime has been initialized (as we are running in @@ -77,19 +94,7 @@ static int main_running = 0; void ANativeActivity_onCreate(ANativeActivity *activity, void* savedState, size_t savedStateSize) { if (!main_running) { JNIEnv* env = activity->env; - - // Note that activity->clazz is mis-named. - current_class = (*env)->GetObjectClass(env, activity->clazz); - current_class = (*env)->NewGlobalRef(env, current_class); - key_rune_method = find_static_method(env, current_class, "getRune", "(III)I"); - show_keyboard_method = find_static_method(env, current_class, "showKeyboard", "(I)V"); - hide_keyboard_method = find_static_method(env, current_class, "hideKeyboard", "()V"); - show_file_open_method = find_static_method(env, current_class, "showFileOpen", "(Ljava/lang/String;)V"); - show_file_save_method = find_static_method(env, current_class, "showFileSave", "(Ljava/lang/String;Ljava/lang/String;)V"); - finish_method = find_method(env, current_class, "finishActivity", "()V"); - - setCurrentContext(activity->vm, (*env)->NewGlobalRef(env, activity->clazz)); - + set_global(activity); // useless? OnStart? // Set FILESDIR if (setenv("FILESDIR", activity->internalDataPath, 1) != 0) { LOG_INFO("setenv(\"FILESDIR\", \"%s\", 1) failed: %d", activity->internalDataPath, errno); @@ -281,10 +286,6 @@ void Java_org_golang_app_GoNativeActivity_keyboardDelete(JNIEnv *env, jclass cla keyboardDelete(); } -void Java_org_golang_app_GoNativeActivity_backPressed(JNIEnv *env, jclass clazz) { - onBackPressed(); -} - void Java_org_golang_app_GoNativeActivity_setDarkMode(JNIEnv *env, jclass clazz, jboolean dark) { setDarkMode((bool)dark); } diff --git a/internal/driver/mobile/app/android.go b/internal/driver/mobile/app/android.go index fdc09b8597..d7f1707631 100644 --- a/internal/driver/mobile/app/android.go +++ b/internal/driver/mobile/app/android.go @@ -49,6 +49,7 @@ void hideKeyboard(JNIEnv* env); void showFileOpen(JNIEnv* env, char* mimes); void showFileSave(JNIEnv* env, char* mimes, char* filename); void finish(JNIEnv* env, jobject ctx); +void set_global(ANativeActivity *activity); void Java_org_golang_app_GoNativeActivity_filePickerReturned(JNIEnv *env, jclass clazz, jstring str); */ @@ -78,18 +79,6 @@ var mimeMap = map[string]string{ ".txt": "text/plain", } -// GoBack asks the OS to go to the previous app / activity -func GoBack() { - err := RunOnJVM(func(_, jniEnv, ctx uintptr) error { - env := (*C.JNIEnv)(unsafe.Pointer(jniEnv)) - C.finish(env, C.jobject(ctx)) - return nil - }) - if err != nil { - log.Fatalf("app: %v", err) - } -} - // RunOnJVM runs fn on a new goroutine locked to an OS thread with a JNIEnv. // // RunOnJVM blocks until the call to fn is complete. Any Java @@ -133,10 +122,12 @@ func callMain(mainPC uintptr) { //export onStart func onStart(activity *C.ANativeActivity) { + C.set_global(activity) } //export onResume func onResume(activity *C.ANativeActivity) { + C.set_global(activity) } //export onSaveInstanceState @@ -152,7 +143,6 @@ func onPause(activity *C.ANativeActivity) { func onStop(activity *C.ANativeActivity) { } -//export onBackPressed func onBackPressed() { k := key.Event{ Code: key.CodeBackButton, @@ -230,6 +220,15 @@ type windowConfig struct { pixelsPerPt float32 } +func Finish() { + RunOnJVM(func(vm, jniEnv, ctx uintptr) error { + println("finish") + env := (*C.JNIEnv)(unsafe.Pointer(jniEnv)) // not a Go heap pointer + C.finish(env, C.jobject(ctx)) + return nil + }) +} + func windowConfigRead(activity *C.ANativeActivity) windowConfig { aconfig := C.AConfiguration_new() C.AConfiguration_fromAssetManager(aconfig, activity.assetManager) @@ -555,21 +554,22 @@ func runInputQueue(vm, jniEnv, ctx uintptr) error { } } + func processEvents(env *C.JNIEnv, q *C.AInputQueue) { var e *C.AInputEvent for C.AInputQueue_getEvent(q, &e) >= 0 { if C.AInputQueue_preDispatchEvent(q, e) != 0 { continue } - processEvent(env, e) - C.AInputQueue_finishEvent(q, e, 0) + handle := processEvent(env, e) + C.AInputQueue_finishEvent(q, e, C.int(handle)) } } -func processEvent(env *C.JNIEnv, e *C.AInputEvent) { +func processEvent(env *C.JNIEnv, e *C.AInputEvent) int { switch C.AInputEvent_getType(e) { case C.AINPUT_EVENT_TYPE_KEY: - processKey(env, e) + return processKey(env, e) case C.AINPUT_EVENT_TYPE_MOTION: // At most one of the events in this batch is an up or down event; get its index and change. upDownIndex := C.size_t(C.AMotionEvent_getAction(e)&C.AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> C.AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT @@ -596,21 +596,29 @@ func processEvent(env *C.JNIEnv, e *C.AInputEvent) { default: log.Printf("unknown input event, type=%d", C.AInputEvent_getType(e)) } + return 0 } -func processKey(env *C.JNIEnv, e *C.AInputEvent) { +func processKey(env *C.JNIEnv, e *C.AInputEvent) int { deviceID := C.AInputEvent_getDeviceId(e) if deviceID == 0 { // Software keyboard input, leaving for scribe/IME. - return + return 0 + } + keyCode := C.AKeyEvent_getKeyCode(e) + if (keyCode == C.AKEYCODE_BACK) { + println("back ok") + go onBackPressed() + return 1 // Handle back button press and return handle + } else if (keyCode == C.AKEYCODE_MENU) { + return 1 // Handle menu button press } - k := key.Event{ Rune: rune(C.getKeyRune(env, e)), - Code: convAndroidKeyCode(int32(C.AKeyEvent_getKeyCode(e))), + Code: convAndroidKeyCode(int32(keyCode)), } if k.Rune >= '0' && k.Rune <= '9' { // GBoard generates key events for numbers, but we see them in textChanged - return + return 0 } switch C.AKeyEvent_getAction(e) { case C.AKEY_STATE_DOWN: @@ -621,7 +629,8 @@ func processKey(env *C.JNIEnv, e *C.AInputEvent) { k.Direction = key.DirNone } // TODO(crawshaw): set Modifiers. - theApp.events.In() <- k + go func() {theApp.events.In() <- k}() + return 0 } func eglGetError() string { diff --git a/internal/driver/mobile/app/darwin_desktop.go b/internal/driver/mobile/app/darwin_desktop.go index 5b7041f465..d34a522a3e 100644 --- a/internal/driver/mobile/app/darwin_desktop.go +++ b/internal/driver/mobile/app/darwin_desktop.go @@ -63,10 +63,6 @@ func main(f func(App)) { C.runApp() } -func GoBack() { - // When simulating mobile there are no other activities open (and we can't just force background) -} - // loop is the primary drawing loop. // // After Cocoa has captured the initial OS thread for processing Cocoa @@ -108,6 +104,8 @@ func (a *app) loop(ctx C.GLintptr) { } } +func Finish() {} + var drawDone = make(chan struct{}) // drawgl is used by Cocoa to occasionally request screen updates. diff --git a/internal/driver/mobile/app/darwin_ios.go b/internal/driver/mobile/app/darwin_ios.go index d40ec5a29e..dd5860d67e 100644 --- a/internal/driver/mobile/app/darwin_ios.go +++ b/internal/driver/mobile/app/darwin_ios.go @@ -82,10 +82,6 @@ var DisplayMetrics struct { HeightPx int } -func GoBack() { - // Apple do not permit apps to exit in any way other than user pressing home button / gesture -} - //export setDisplayMetrics func setDisplayMetrics(width, height int, scale int) { DisplayMetrics.WidthPx = width @@ -151,6 +147,8 @@ func updateConfig(width, height, orientation int32) { theApp.events.In() <- paint.Event{External: true} } +func Finish() {} + // touchIDs is the current active touches. The position in the array // is the ID, the value is the UITouch* pointer value. // diff --git a/internal/driver/mobile/app/shiny.go b/internal/driver/mobile/app/shiny.go index 8784215080..3012b07255 100644 --- a/internal/driver/mobile/app/shiny.go +++ b/internal/driver/mobile/app/shiny.go @@ -15,8 +15,7 @@ func main(f func(a App)) { fmt.Errorf("Running mobile simulation mode does not currently work on Windows.") } -func GoBack() { - // When simulating mobile there are no other activities open (and we can't just force background) +func Finish() { // When simulating mobile there are no other activities open (and we can't just force background) } // driverShowVirtualKeyboard does nothing on desktop diff --git a/internal/driver/mobile/app/x11.go b/internal/driver/mobile/app/x11.go index 300297c3b1..27ccf342fb 100644 --- a/internal/driver/mobile/app/x11.go +++ b/internal/driver/mobile/app/x11.go @@ -80,9 +80,7 @@ func main(f func(App)) { } } -func GoBack() { - // When simulating mobile there are no other activities open (and we can't just force background) -} +func Finish() {} //export onResize func onResize(w, h int) { diff --git a/internal/driver/mobile/driver.go b/internal/driver/mobile/driver.go index 32ef317b54..3fae9b7390 100644 --- a/internal/driver/mobile/driver.go +++ b/internal/driver/mobile/driver.go @@ -128,11 +128,8 @@ func (d *mobileDriver) AbsolutePositionForObject(co fyne.CanvasObject) fyne.Posi return pos.Subtract(inset) } -func (d *mobileDriver) GoBack() { - app.GoBack() -} - func (d *mobileDriver) Quit() { + app.Finish() // Android and iOS guidelines say this should not be allowed! } diff --git a/internal/driver/mobile/mobileinit/ctx_android.go b/internal/driver/mobile/mobileinit/ctx_android.go index b58881a26d..8a109ee29b 100644 --- a/internal/driver/mobile/mobileinit/ctx_android.go +++ b/internal/driver/mobile/mobileinit/ctx_android.go @@ -55,6 +55,13 @@ static char* checkException(uintptr_t jnienv) { static void unlockJNI(JavaVM *vm) { (*vm)->DetachCurrentThread(vm); } +static void deletePrevCtx(JNIEnv* env,jobject ctx){ + (*env)->DeleteGlobalRef(env, ctx); +} +static int is_null(jobject ctx){ + if (ctx == NULL) return 1; + return 0; +} */ import "C" @@ -80,6 +87,13 @@ var currentCtx C.jobject // The android.context.Context object must be a global reference. func SetCurrentContext(vm unsafe.Pointer, ctx uintptr) { currentVM = (*C.JavaVM)(vm) + if int(C.is_null(currentCtx)) == 1 { + RunOnJVM(func(vm, jniEnv, ctx uintptr) error { + env := (*C.JNIEnv)(unsafe.Pointer(jniEnv)) // not a Go heap pointer + C.deletePrevCtx(env, C.jobject(ctx)) + return nil + }) + } currentCtx = (C.jobject)(ctx) }