app: add RegisterFragment method on *Window for Android

RegisterFragment creates an instance of a Java class and registers
it as a Fragment in the window's Context.

Signed-off-by: Greg Pomerantz <gmp.gio@wow.st>
This commit is contained in:
Greg Pomerantz
2019-11-26 12:47:54 -05:00
committed by Elias Naur
parent ce76c2e996
commit 2ca2e5462f
8 changed files with 98 additions and 16 deletions
-7
View File
@@ -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
+30
View File
@@ -0,0 +1,30 @@
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)
}
// androidDriver is an interface that allows the Window's run method
// to call the RegisterFragment method of the Android window driver.
type androidDriver interface {
RegisterFragment(string)
}
// RegisterFragment constructs a Java instance of the specified class
// and registers it as a Fragment in the Context in which the View was
// created.
func (w *Window) RegisterFragment(del string) {
go func() {
w.driverFuncs <- func() {
d := w.driver.(androidDriver)
d.RegisterFragment(del)
}
}()
}
+41 -2
View File
@@ -2,12 +2,21 @@
package org.gioui;
import java.lang.Class;
import java.lang.IllegalAccessException;
import java.lang.InstantiationException;
import java.lang.ExceptionInInitializerError;
import java.lang.SecurityException;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
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.view.Choreographer;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
@@ -57,11 +66,12 @@ public class GioView extends SurfaceView implements Choreographer.FrameCallback
public GioView(Context context, AttributeSet attrs) {
super(context, attrs);
handler = new Handler();
// Late initialization of the Go runtime to wait for a valid context.
initialize(context.getApplicationContext());
nhandle = onCreateView(this);
handler = new Handler();
imm = (InputMethodManager)context.getSystemService(Context.INPUT_METHOD_SERVICE);
setFocusable(true);
setFocusableInTouchMode(true);
@@ -207,6 +217,35 @@ public class GioView extends SurfaceView implements Choreographer.FrameCallback
return onBack(nhandle);
}
public void registerFragment(String del) {
final Class cls;
try {
cls = getContext().getClassLoader().loadClass(del);
} catch (ClassNotFoundException e) {
throw new RuntimeException("RegisterFragment: fragment class not found: " + e.getMessage());
}
handler.post(new Runnable() {
public void run() {
final Fragment frag;
try {
frag = (Fragment)cls.newInstance();
} catch (IllegalAccessException | InstantiationException | ExceptionInInitializerError | SecurityException | ClassCastException e) {
throw new RuntimeException("RegisterFragment: error instantiating fragment: " + e.getMessage());
}
final FragmentManager fm;
try {
fm = ((Activity)getContext()).getFragmentManager();
} catch (ClassCastException e) {
throw new RuntimeException("RegisterFragment: cannot get fragment manager from View Context: " + e.getMessage());
}
FragmentTransaction ft = fm.beginTransaction();
ft.add(frag, del);
ft.commitNow();
}
});
}
static private native long onCreateView(GioView view);
static private native void onDestroyView(long handle);
static private native void onStartView(long handle);
-7
View File
@@ -1,7 +0,0 @@
// +build !android
package window
var PlatformHandle *Handle
type Handle struct{}
+5
View File
@@ -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_RegisterFragment(JNIEnv *env, jobject view, jmethodID mid, char* del) {
jstring jdel = (*env)->NewStringUTF(env, del);
(*env)->CallObjectMethod(env, view, mid, jdel);
}
+10
View File
@@ -54,6 +54,7 @@ type window struct {
mhideTextInput C.jmethodID
mpostFrameCallback C.jmethodID
mpostFrameCallbackOnMainThread C.jmethodID
mRegisterFragment 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"),
mRegisterFragment: jniGetMethodID(env, class, "registerFragment", "(Ljava/lang/String;)V"),
}
wopts := <-mainWindow.out
w.callbacks = wopts.window
@@ -443,6 +445,14 @@ func (w *window) ShowTextInput(show bool) {
})
}
func (w *window) RegisterFragment(del string) {
runInJVM(func(env *C.JNIEnv) {
cdel := C.CString(del)
defer C.free(unsafe.Pointer(cdel))
C.gio_jni_RegisterFragment(env, w.view, w.mRegisterFragment, cdel)
})
}
func Main() {
}
+1
View File
@@ -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);
__attribute__ ((visibility ("hidden"))) void gio_jni_RegisterFragment(JNIEnv *env, jobject view, jmethodID mid, char* del);
+11
View File
@@ -29,6 +29,10 @@ type Window struct {
driver window.Driver
gpu *gpu.GPU
// driverFuncs is a channel of functions to run when
// the Window has a valid driver.
driverFuncs chan func()
out chan event.Event
in chan event.Event
ack chan struct{}
@@ -95,6 +99,7 @@ func NewWindow(options ...Option) *Window {
invalidates: make(chan struct{}, 1),
frames: make(chan *op.Ops),
frameAck: make(chan struct{}),
driverFuncs: make(chan func()),
}
w.callbacks.w = w
go w.run(opts)
@@ -227,6 +232,10 @@ func (w *Window) run(opts *window.Options) {
return
}
for {
var driverFuncs chan func() = nil
if w.driver != nil {
driverFuncs = w.driverFuncs
}
var timer <-chan time.Time
if w.delayedDraw != nil {
timer = w.delayedDraw.C
@@ -238,6 +247,8 @@ func (w *Window) run(opts *window.Options) {
case <-w.invalidates:
w.setNextFrame(time.Time{})
w.updateAnimation()
case f := <-driverFuncs:
f()
case e := <-w.in:
switch e2 := e.(type) {
case system.StageEvent: