256 lines
7.7 KiB
Go
256 lines
7.7 KiB
Go
package ble
|
|
|
|
/*
|
|
#cgo LDFLAGS: -landroid -llog
|
|
|
|
#include <stdlib.h>
|
|
#include <jni.h>
|
|
#include <android/log.h>
|
|
|
|
static jobject gClassLoader;
|
|
static jmethodID gFindClassMethod;
|
|
|
|
jclass
|
|
GetObjectClass(JNIEnv* env, jobject obj) {
|
|
jclass cls = (*env)->GetObjectClass(env, obj);
|
|
cls = (*env)->NewGlobalRef(env, cls);
|
|
return cls;
|
|
}
|
|
|
|
void
|
|
SetLoader(JNIEnv* env, jobject context) {
|
|
jclass cclass = (*env)->GetObjectClass(env, context);
|
|
jmethodID gcl_id = (*env)->GetMethodID(env, cclass, "getClassLoader", "()Ljava/lang/ClassLoader;");
|
|
jobject loader = (*env)->CallObjectMethod(env, context, gcl_id);
|
|
gClassLoader = (*env)->NewGlobalRef(env, loader);
|
|
jclass lclass = (*env)->GetObjectClass(env, loader);
|
|
gFindClassMethod = (*env)->GetMethodID(env, lclass, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;");
|
|
}
|
|
|
|
jclass
|
|
FindClass(JNIEnv* env, char* name) {
|
|
jstring strClassName = (*env)->NewStringUTF(env, name);
|
|
return (*env)->CallObjectMethod(env, gClassLoader, gFindClassMethod, strClassName);
|
|
}
|
|
|
|
void
|
|
EnableBluetooth(JNIEnv* env, jobject ctx, jobject ad) {
|
|
__android_log_write(ANDROID_LOG_DEBUG, "gio", "Finding BleUtil");
|
|
jclass cls = FindClass(env, "st/wow/git/ble/BleUtil");
|
|
if (cls == NULL) {
|
|
__android_log_write(ANDROID_LOG_DEBUG, "gio", "not found");
|
|
return;
|
|
}
|
|
__android_log_write(ANDROID_LOG_DEBUG, "gio", "getting <init>");
|
|
jmethodID mid = (*env)->GetMethodID(env, cls, "<init>", "()V");
|
|
if (mid == NULL) {
|
|
__android_log_write(ANDROID_LOG_DEBUG, "gio", "not found");
|
|
return;
|
|
}
|
|
__android_log_write(ANDROID_LOG_DEBUG, "gio", "calling NewObject");
|
|
jobject bleutil = (*env)->NewObject(env, cls, mid);
|
|
if (bleutil == NULL) {
|
|
__android_log_write(ANDROID_LOG_DEBUG, "gio", "failed");
|
|
return;
|
|
}
|
|
__android_log_write(ANDROID_LOG_DEBUG, "gio", "Getting Enable()");
|
|
mid = (*env)->GetMethodID(env, cls, "Enable", "(Landroid/content/Context;)V");
|
|
if (mid == NULL) {
|
|
__android_log_write(ANDROID_LOG_DEBUG, "gio", "failed");
|
|
return;
|
|
}
|
|
__android_log_write(ANDROID_LOG_DEBUG, "gio", "Calling Enable()");
|
|
(*env)->CallVoidMethod(env, bleutil, mid, ctx);
|
|
}
|
|
|
|
jobject
|
|
GetBluetoothAdapter(JNIEnv* env, jobject ctx) {
|
|
jclass cls = (*env)->GetObjectClass(env, ctx);
|
|
if (cls == NULL) {
|
|
__android_log_write(ANDROID_LOG_DEBUG, "gio", "GetBluetoothAdapter(): Can't get context class");
|
|
return NULL;
|
|
}
|
|
jfieldID id = (*env)->GetStaticFieldID(env, cls, "BLUETOOTH_SERVICE", "Ljava/lang/String;");
|
|
if (id == NULL) {
|
|
__android_log_write(ANDROID_LOG_DEBUG, "gio", "GetBluetoothAdapter(): Can't get field ID");
|
|
return NULL;
|
|
}
|
|
jstring btsrv = (jstring)(*env)->GetStaticObjectField(env, cls, id);
|
|
if (btsrv == NULL) {
|
|
__android_log_write(ANDROID_LOG_DEBUG, "gio", "GetBluetoothAdapter(): Can't get static object field");
|
|
return NULL;
|
|
}
|
|
jmethodID mid = (*env)->GetMethodID(env, cls, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
|
|
if (mid == NULL) {
|
|
__android_log_write(ANDROID_LOG_DEBUG, "gio", "GetBluetoothAdapter(): Can't get method ID");
|
|
return NULL;
|
|
}
|
|
jobject manager = (*env)->CallObjectMethod(env, ctx, mid, btsrv);
|
|
if (manager == NULL) {
|
|
__android_log_write(ANDROID_LOG_DEBUG, "gio", "GetBluetoothAdapter(): Can't get bluetooth manager");
|
|
return NULL;
|
|
}
|
|
cls = (*env)->GetObjectClass(env, manager);
|
|
if (cls == NULL) {
|
|
__android_log_write(ANDROID_LOG_DEBUG, "gio", "GetBluetoothAdapter(): Can't get class of bluetooth manager");
|
|
return NULL;
|
|
}
|
|
mid = (*env)->GetMethodID(env, cls, "getAdapter", "()Landroid/bluetooth/BluetoothAdapter;");
|
|
if (mid == NULL) {
|
|
__android_log_write(ANDROID_LOG_DEBUG, "gio", "GetBluetoothAdapter(): Can't get methodID for getAdapter()");
|
|
return NULL;
|
|
}
|
|
jobject ad = (*env)->CallObjectMethod(env, manager, mid);
|
|
if (ad == NULL) {
|
|
__android_log_write(ANDROID_LOG_DEBUG, "gio", "GetBluetoothAdapter(): Can't get adapter");
|
|
} else {
|
|
__android_log_write(ANDROID_LOG_DEBUG, "gio", "GetBluetoothAdapter(): Found");
|
|
}
|
|
|
|
ad = (*env)->NewGlobalRef(env, ad);
|
|
|
|
EnableBluetooth(env, ctx, ad);
|
|
return ad;
|
|
}
|
|
|
|
jstring
|
|
GetObjectStaticStringField(JNIEnv* env, jobject obj, char* fld) {
|
|
jclass cls = (*env)->GetObjectClass(env, obj);
|
|
if (cls == NULL) {
|
|
__android_log_write(ANDROID_LOG_DEBUG, "gio", "GetObjectStaticStringField(): Can't get class");
|
|
return NULL;
|
|
}
|
|
jfieldID id = (*env)->GetStaticFieldID(env, cls, fld, "Ljava/lang/String;");
|
|
if (id == NULL) {
|
|
__android_log_write(ANDROID_LOG_DEBUG, "gio", "GetObjectStaticStringField(): Can't find FieldID");
|
|
return NULL;
|
|
}
|
|
return (jstring)(*env)->GetStaticObjectField(env, cls, id);
|
|
}
|
|
|
|
JNIEXPORT jobject
|
|
CreateObject(JNIEnv* env, jclass cls) {
|
|
jmethodID init = (*env)->GetMethodID(env, cls, "<init>", "()V");
|
|
return (*env)->NewObject(env, cls, init);
|
|
}
|
|
|
|
void CallVoidMethod(JNIEnv *env, jobject obj, jmethodID methodID) {
|
|
(*env)->CallVoidMethod(env, obj, methodID);
|
|
}
|
|
|
|
jboolean CallBooleanMethod(JNIEnv *env, jobject obj, jmethodID mid) {
|
|
return (*env)->CallBooleanMethod(env, obj, mid);
|
|
}
|
|
|
|
jint CallIntMethod(JNIEnv *env, jobject obj, jmethodID methodID) {
|
|
return (*env)->CallIntMethod(env, obj, methodID);
|
|
}
|
|
|
|
jmethodID GetMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig) {
|
|
return (*env)->GetMethodID(env, clazz, name, sig);
|
|
}
|
|
|
|
jint GetEnv(JavaVM *vm, JNIEnv **env, jint version) {
|
|
return (*vm)->GetEnv(vm, (void **)env, version);
|
|
}
|
|
|
|
jint AttachCurrentThread(JavaVM *vm, JNIEnv **p_env, void *thr_args) {
|
|
return (*vm)->AttachCurrentThread(vm, p_env, thr_args);
|
|
}
|
|
|
|
jint DetachCurrentThread(JavaVM *vm) {
|
|
return (*vm)->DetachCurrentThread(vm);
|
|
}
|
|
|
|
*/
|
|
import "C"
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"runtime"
|
|
"unsafe"
|
|
)
|
|
|
|
var theJVM *C.JavaVM
|
|
|
|
type JNIEnv = C.JNIEnv
|
|
|
|
func setJVM(jvm, context uintptr) {
|
|
log.Print("set theJVM")
|
|
theJVM = (*C.JavaVM)(unsafe.Pointer(jvm))
|
|
//log.Printf("theJVM = %d", uintptr(unsafe.Pointer(theJVM)))
|
|
RunInJVM(func(env *C.JNIEnv) {
|
|
C.SetLoader(env, (C.jobject)(context))
|
|
})
|
|
}
|
|
|
|
func FindClass(env *C.JNIEnv, name string) C.jclass {
|
|
cname := C.CString(name)
|
|
defer C.free(unsafe.Pointer(cname))
|
|
return C.FindClass((*C.JNIEnv)(env), cname)
|
|
}
|
|
|
|
func JniGetObjectClass(env *C.JNIEnv, obj C.jobject) C.jclass {
|
|
return C.GetObjectClass(env, obj)
|
|
}
|
|
|
|
func JniGetObjectStaticStringField(env *C.JNIEnv, obj C.jobject, fld string) C.jstring {
|
|
cstring := C.CString(fld)
|
|
defer C.free(unsafe.Pointer(cstring))
|
|
return C.GetObjectStaticStringField(env, obj, cstring)
|
|
}
|
|
|
|
func GetBluetoothAdapter(env *C.JNIEnv, ctx uintptr) C.jobject {
|
|
return C.GetBluetoothAdapter(env, (C.jobject)(ctx))
|
|
}
|
|
|
|
func JniCallVoidMethod(env *C.JNIEnv, obj C.jobject, methodID C.jmethodID) {
|
|
C.CallVoidMethod(env, obj, methodID)
|
|
}
|
|
|
|
func JniCallBooleanMethod(env *C.JNIEnv, obj C.jobject, methodID C.jmethodID) bool {
|
|
return C.CallBooleanMethod(env, obj, methodID) == C.JNI_TRUE
|
|
}
|
|
|
|
func JniCallIntMethod(env *C.JNIEnv, obj C.jobject, methodID C.jmethodID) int {
|
|
return (int)(C.CallIntMethod(env, obj, methodID))
|
|
}
|
|
|
|
func JniGetMethodID(env *C.JNIEnv, cls C.jclass, name, sig string) C.jmethodID {
|
|
cname := C.CString(name)
|
|
defer C.free(unsafe.Pointer(cname))
|
|
csig := C.CString(sig)
|
|
defer C.free(unsafe.Pointer(csig))
|
|
return C.GetMethodID(env, cls, cname, csig)
|
|
}
|
|
|
|
func CreateObject(env *C.JNIEnv, cls C.jclass) C.jobject {
|
|
return C.CreateObject(env, (C.jclass)(cls))
|
|
}
|
|
|
|
func RunInJVM(f func(env *C.JNIEnv)) {
|
|
runtime.LockOSThread()
|
|
defer runtime.UnlockOSThread()
|
|
var env *C.JNIEnv
|
|
var detach bool
|
|
//log.Printf("RunInJVM(): theJVM = %d", uintptr(unsafe.Pointer(theJVM)))
|
|
if res := C.GetEnv(theJVM, &env, C.JNI_VERSION_1_6); res != C.JNI_OK {
|
|
if res != C.JNI_EDETACHED {
|
|
panic(fmt.Errorf("JNI GetEnv failed with error %d", res))
|
|
}
|
|
if C.AttachCurrentThread(theJVM, &env, nil) != C.JNI_OK {
|
|
panic(errors.New("runInJVM: AttachCurrentThread failed"))
|
|
}
|
|
detach = true
|
|
}
|
|
|
|
if detach {
|
|
defer func() {
|
|
C.DetachCurrentThread(theJVM)
|
|
}()
|
|
}
|
|
f(env)
|
|
}
|