~eliasnaur/gio

app: add RegisterDelegate method on *Window for Android v1 PROPOSED

Greg Pomerantz
Greg Pomerantz: 2
 app: add RegisterDelegate method on *Window for Android
 app/permission: add storage permissions

 10 files changed, 92 insertions(+), 23 deletions(-)
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~eliasnaur/gio/patches/9095/mbox | git am -3
Learn more about email & git
View this thread in the archives

[PATCH 1/2] app: add RegisterDelegate method on *Window for Android Export this patch

Greg Pomerantz
RegisterDelegate creates an instance of a Java class and passes
a window's Activity to its constructor.

Signed-off-by: Greg Pomerantz <gmp.gio@wow.st>
---
 app/app.go                           |  7 -----
 app/app_android.go                   | 20 +++++++++++++
 app/internal/window/GioActivity.java |  2 +-
 app/internal/window/GioView.java     | 54 ++++++++++++++++++++++++++++++------
 app/internal/window/handle.go        |  7 -----
 app/internal/window/os_android.c     |  5 ++++
 app/internal/window/os_android.go    | 14 ++++++++++
 app/internal/window/os_android.h     |  1 +
 8 files changed, 87 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..a33c990
--- /dev/null
+++ b/app/app_android.go
@@ -0,0 +1,20 @@
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)
}

// RegisterDelegate constructs a Java instance of the specified class
// and calls its public initView(android.app.Activity) constructor with
// the Activity that created the window.
func (w *Window) RegisterDelegate(del string) {
	d := w.driver.(window.AndroidDriver)
	d.RegisterDelegate(del)
}
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..38f6c6e 100644
--- a/app/internal/window/GioView.java
+++ b/app/internal/window/GioView.java
@@ -2,12 +2,18 @@

package org.gioui;

import java.lang.Class;
import java.lang.ClassLoader;
import java.lang.reflect.Constructor;
import java.lang.Throwable;
import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.os.Handler;
import android.util.AttributeSet;
import android.text.Editable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Choreographer;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
@@ -31,7 +37,9 @@ public class GioView extends SurfaceView implements Choreographer.FrameCallback
	private final SurfaceHolder.Callback callbacks;
	private final InputMethodManager imm;
	private final Handler handler;
	private final ClassLoader classloader;
	private long nhandle;
	private Activity activity;

	private static synchronized void initialize(Context appCtx) {
		synchronized (initLock) {
@@ -51,18 +59,19 @@ 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());

		classloader = GioView.class.getClassLoader();
		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 +190,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 +219,32 @@ public class GioView extends SurfaceView implements Choreographer.FrameCallback
		return onBack(nhandle);
	}

	public void RegisterDelegate(String del) {
		handler.post(new Runnable() {
			public void run() {
				Class cls;
				try {
					cls = classloader.loadClass(del);
				} catch (ClassNotFoundException ignored) {
					Log.e("gio", "RegisterDelegate: Class " + del + "not found");
					return;
				}
				Constructor init;
				try {
					init = cls.getConstructor(Activity.class);
				} catch (NoSuchMethodException ignored) {
					Log.e("gio", "RegisterDelegate: constructor not found for " + del);
					return;
				}
				try {
					init.newInstance(activity);
				} catch (Throwable e) {
					Log.e("gio", "RegisterDelegate: constructor failed: " + e.getMessage());
				}
			}
		});
	}

	static private native long onCreateView(GioView view);
	static private native void onDestroyView(long handle);
	static private native void onStartView(long handle);
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..59d0da2 100644
--- a/app/internal/window/os_android.c
+++ b/app/internal/window/os_android.c
@@ -166,3 +166,8 @@ 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_RegisterDelegate(JNIEnv *env, jobject view, jmethodID mid, char* del) {
	jstring jdel = (*env)->NewStringUTF(env, del);
	(*env)->CallVoidMethod(env, view, mid, jdel);
}
diff --git a/app/internal/window/os_android.go b/app/internal/window/os_android.go
index 5cce88d..7ace02d 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
	mRegisterDelegate              C.jmethodID
}

var dataDirChan = make(chan string, 1)
@@ -119,6 +120,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"),
		mRegisterDelegate:              jniGetMethodID(env, class, "RegisterDelegate", "(Ljava/lang/String;)V"),
	}
	wopts := <-mainWindow.out
	w.callbacks = wopts.window
@@ -443,6 +445,18 @@ func (w *window) ShowTextInput(show bool) {
	})
}

type AndroidDriver interface {
	RegisterDelegate(string)
}

func (w *window) RegisterDelegate(del string) {
	runInJVM(func(env *C.JNIEnv) {
		cdel := C.CString(del)
		defer C.free(unsafe.Pointer(cdel))
		C.gio_jni_RegisterDelegate(env, w.view, w.mRegisterDelegate, cdel)
	})
}

func Main() {
}

diff --git a/app/internal/window/os_android.h b/app/internal/window/os_android.h
index 288d633..8f9c101 100644
--- a/app/internal/window/os_android.h
+++ b/app/internal/window/os_android.h
@@ -17,3 +17,4 @@ __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);
void gio_jni_RegisterDelegate(JNIEnv *env, jobject view, jmethodID mid, char* del);
-- 
2.16.2
Thank you, this is looking quite clean.

On Wed Nov 20, 2019 at 5:27 PM Greg Pomerantz wrote:

[PATCH 2/2] app/permission: add storage permissions Export this patch

Greg Pomerantz
Storage permissions enables the Android permissions
READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE.
---
 app/permission/storage/main.go | 1 +
 cmd/gogio/permission.go        | 4 ++++
 2 files changed, 5 insertions(+)
 create mode 100644 app/permission/storage/main.go

diff --git a/app/permission/storage/main.go b/app/permission/storage/main.go
new file mode 100644
index 0000000..82be054
--- /dev/null
+++ b/app/permission/storage/main.go
@@ -0,0 +1 @@
package storage
diff --git a/cmd/gogio/permission.go b/cmd/gogio/permission.go
index eabbb91..a39f1b8 100644
--- a/cmd/gogio/permission.go
+++ b/cmd/gogio/permission.go
@@ -14,6 +14,10 @@ var AndroidPermissions = map[string][]string{
		"android.permission.BLUETOOTH_ADMIN",
		"android.permission.ACCESS_FINE_LOCATION",
	},
	"storage": {
		"android.permission.READ_EXTERNAL_STORAGE",
		"android.permission.WRITE_EXTERNAL_STORAGE",
	},
}

var AndroidFeatures = map[string][]string{
-- 
2.16.2