Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for responding to back button on Android #3948

Merged
merged 5 commits into from
Aug 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
439 changes: 224 additions & 215 deletions cmd/fyne/internal/mobile/dex.go

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions driver/mobile/driver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Package mobile provides desktop specific mobile functionality.
package mobile

// Driver represents the extended capabilities of a mobile driver
//
// Since: 2.4
type Driver interface {
// GoBack asks the OS to go to the previous app / activity, where supported
GoBack()
}
10 changes: 10 additions & 0 deletions driver/mobile/key.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package mobile

import (
"fyne.io/fyne/v2"
)

const (
// KeyBack represents the back button which may be hardware or software
KeyBack fyne.KeyName = "Back"
)
16 changes: 16 additions & 0 deletions internal/driver/mobile/app/GoNativeActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ 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;
Expand Down Expand Up @@ -313,6 +314,21 @@ 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);
Expand Down
23 changes: 22 additions & 1 deletion internal/driver/mobile/app/android.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ static jmethodID show_keyboard_method;
static jmethodID hide_keyboard_method;
static jmethodID show_file_open_method;
static jmethodID show_file_save_method;
static jmethodID finish_method;

jint JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env;
Expand All @@ -65,6 +66,14 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {

static int main_running = 0;

// ensure we refresh context on resume in case something has changed...
void processOnResume(ANativeActivity *activity) {
JNIEnv* env = activity->env;
setCurrentContext(activity->vm, (*env)->NewGlobalRef(env, activity->clazz));

onResume(activity);
}

// Entry point from our subclassed NativeActivity.
//
// By here, the Go runtime has been initialized (as we are running in
Expand All @@ -85,6 +94,7 @@ void ANativeActivity_onCreate(ANativeActivity *activity, void* savedState, size_
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");
andydotxyz marked this conversation as resolved.
Show resolved Hide resolved

setCurrentContext(activity->vm, (*env)->NewGlobalRef(env, activity->clazz));

Expand Down Expand Up @@ -117,7 +127,7 @@ void ANativeActivity_onCreate(ANativeActivity *activity, void* savedState, size_
// Note that onNativeWindowResized is not called on resize. Avoid it.
// https://code.google.com/p/android/issues/detail?id=180645
activity->callbacks->onStart = onStart;
activity->callbacks->onResume = onResume;
activity->callbacks->onResume = processOnResume;
activity->callbacks->onSaveInstanceState = onSaveInstanceState;
activity->callbacks->onPause = onPause;
activity->callbacks->onStop = onStop;
Expand Down Expand Up @@ -204,6 +214,13 @@ char* destroyEGLSurface() {
return NULL;
}

void finish(JNIEnv* env, jobject ctx) {
(*env)->CallVoidMethod(
env,
ctx,
finish_method);
}

int32_t getKeyRune(JNIEnv* env, AInputEvent* e) {
return (int32_t)(*env)->CallStaticIntMethod(
env,
Expand Down Expand Up @@ -272,6 +289,10 @@ 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);
}
26 changes: 26 additions & 0 deletions internal/driver/mobile/app/android.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ void showKeyboard(JNIEnv* env, int keyboardType);
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 Java_org_golang_app_GoNativeActivity_filePickerReturned(JNIEnv *env, jclass clazz, jstring str);
*/
Expand Down Expand Up @@ -77,6 +78,18 @@ 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
Expand Down Expand Up @@ -139,6 +152,19 @@ func onPause(activity *C.ANativeActivity) {
func onStop(activity *C.ANativeActivity) {
}

//export onBackPressed
func onBackPressed() {
k := key.Event{
Code: key.CodeBackButton,
Direction: key.DirPress,
}
log.Println("Logging key event back")
theApp.events.In() <- k

k.Direction = key.DirRelease
theApp.events.In() <- k
}

//export onCreate
func onCreate(activity *C.ANativeActivity) {
// Set the initial configuration.
Expand Down
4 changes: 4 additions & 0 deletions internal/driver/mobile/app/darwin_desktop.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ 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
Expand Down
4 changes: 4 additions & 0 deletions internal/driver/mobile/app/darwin_ios.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ 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
Expand Down
4 changes: 4 additions & 0 deletions internal/driver/mobile/app/shiny.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ 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)
}

// driverShowVirtualKeyboard does nothing on desktop
func driverShowVirtualKeyboard(KeyboardType) {
}
Expand Down
4 changes: 4 additions & 0 deletions internal/driver/mobile/app/x11.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ func main(f func(App)) {
}
}

func GoBack() {
// When simulating mobile there are no other activities open (and we can't just force background)
}

//export onResize
func onResize(w, h int) {
// TODO(nigeltao): don't assume 72 DPI. DisplayWidth and DisplayWidthMM
Expand Down
15 changes: 13 additions & 2 deletions internal/driver/mobile/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/driver/mobile"
"fyne.io/fyne/v2/internal"
"fyne.io/fyne/v2/internal/animation"
intapp "fyne.io/fyne/v2/internal/app"
Expand Down Expand Up @@ -127,6 +128,10 @@ func (d *mobileDriver) AbsolutePositionForObject(co fyne.CanvasObject) fyne.Posi
return pos.Subtract(inset)
}

func (d *mobileDriver) GoBack() {
app.GoBack()
}

func (d *mobileDriver) Quit() {
// Android and iOS guidelines say this should not be allowed!
}
Expand Down Expand Up @@ -458,6 +463,8 @@ var keyCodeMap = map[key.Code]fyne.KeyName{
key.CodeBackslash: fyne.KeyBackslash,
key.CodeRightSquareBracket: fyne.KeyRightBracket,
key.CodeGraveAccent: fyne.KeyBackTick,

key.CodeBackButton: mobile.KeyBack,
}

func keyToName(code key.Code) fyne.KeyName {
Expand Down Expand Up @@ -508,8 +515,12 @@ func (d *mobileDriver) typeDownCanvas(canvas *mobileCanvas, r rune, code key.Cod
canvas.Focused().TypedRune(r)
}
} else {
if keyName != "" && canvas.onTypedKey != nil {
canvas.onTypedKey(keyEvent)
if keyName != "" {
if canvas.onTypedKey != nil {
canvas.onTypedKey(keyEvent)
} else if keyName == mobile.KeyBack {
d.GoBack()
}
}
if r > 0 && canvas.onTypedRune != nil {
canvas.onTypedRune(r)
Expand Down
2 changes: 2 additions & 0 deletions internal/driver/mobile/event/key/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ const (
CodeRightAlt Code = 230
CodeRightGUI Code = 231

CodeBackButton Code = 301 // anything above 255 is not used in the USB spec

// The following codes are not part of the standard USB HID Usage IDs for
// keyboards. See http://www.usb.org/developers/hidpage/Hut1_12v2.pdf
//
Expand Down