On Android startup, obtain a Bluetooth adapter and check if it is
enabled.
This commit is contained in:
parent
f036c5e134
commit
820186e132
|
@ -1,14 +1,22 @@
|
||||||
package ble
|
package ble
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
"gioui.org/app"
|
"gioui.org/app"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <jni.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
// Types required for ble.go
|
// Types required for ble.go
|
||||||
|
|
||||||
type bleState string
|
type bleState string
|
||||||
|
|
||||||
type bleHandle struct {
|
type bleHandle struct {
|
||||||
|
adapter C.jobject
|
||||||
|
class C.jclass
|
||||||
}
|
}
|
||||||
|
|
||||||
type Peripheral struct {
|
type Peripheral struct {
|
||||||
|
@ -22,12 +30,16 @@ type Characteristic string
|
||||||
|
|
||||||
// Internal global variables
|
// Internal global variables
|
||||||
|
|
||||||
|
var jvmContext uintptr
|
||||||
|
|
||||||
// Functions required by API
|
// Functions required by API
|
||||||
|
|
||||||
//Init needs to be called before the BLE library can be used. On Android we
|
//Init needs to be called before the BLE library can be used. On Android we
|
||||||
//need to set up the JVM by calling setJVM in jni_android.go.
|
//need to set up the JVM by calling setJVM in jni_android.go.
|
||||||
func Init() {
|
func Init() {
|
||||||
|
log.Print("ble.Init()")
|
||||||
h := app.PlatformHandle()
|
h := app.PlatformHandle()
|
||||||
|
jvmContext = h.Context
|
||||||
setJVM(h.JVM, h.Context)
|
setJVM(h.JVM, h.Context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,6 +110,31 @@ func (p Peripheral) SetNotifyValue(c Characteristic) {
|
||||||
//Bluetooth API.
|
//Bluetooth API.
|
||||||
func NewBLE() *BLE {
|
func NewBLE() *BLE {
|
||||||
ps := Peripherals{items: make([]PeripheralListItem, 0)}
|
ps := Peripherals{items: make([]PeripheralListItem, 0)}
|
||||||
return &BLE{events: make(chan interface{}), peripherals: ps}
|
h := bleHandle{}
|
||||||
|
RunInJVM(func(env *JNIEnv) {
|
||||||
|
h.adapter = GetBluetoothAdapter(env, jvmContext)
|
||||||
|
h.class = JniGetObjectClass(env, h.adapter)
|
||||||
|
})
|
||||||
|
|
||||||
|
ret := &BLE{
|
||||||
|
events: make(chan interface{}),
|
||||||
|
peripherals: ps,
|
||||||
|
handle: h,
|
||||||
|
}
|
||||||
|
|
||||||
|
//check if Bluetooth is enabled and if so, send an UpdateStateEvent
|
||||||
|
go func() {
|
||||||
|
RunInJVM(func(env *JNIEnv) {
|
||||||
|
mid := JniGetMethodID(env, h.class, "isEnabled", "()Z")
|
||||||
|
en := JniCallBooleanMethod(env, h.adapter, mid)
|
||||||
|
if en {
|
||||||
|
log.Print("It's enabled!")
|
||||||
|
ret.events <-UpdateStateEvent{"powered on"}
|
||||||
|
} else {
|
||||||
|
log.Print("It's not enabled")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package ble
|
package ble
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#cgo LDFLAGS: -landroid
|
#cgo LDFLAGS: -landroid -llog
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
|
@ -10,6 +10,13 @@ package ble
|
||||||
static jobject gClassLoader;
|
static jobject gClassLoader;
|
||||||
static jmethodID gFindClassMethod;
|
static jmethodID gFindClassMethod;
|
||||||
|
|
||||||
|
jclass
|
||||||
|
GetObjectClass(JNIEnv* env, jobject obj) {
|
||||||
|
jclass cls = (*env)->GetObjectClass(env, obj);
|
||||||
|
cls = (*env)->NewGlobalRef(env, cls);
|
||||||
|
return cls;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SetLoader(JNIEnv* env, jobject context) {
|
SetLoader(JNIEnv* env, jobject context) {
|
||||||
jclass cclass = (*env)->GetObjectClass(env, context);
|
jclass cclass = (*env)->GetObjectClass(env, context);
|
||||||
|
@ -20,6 +27,68 @@ SetLoader(JNIEnv* env, jobject context) {
|
||||||
gFindClassMethod = (*env)->GetMethodID(env, lclass, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;");
|
gFindClassMethod = (*env)->GetMethodID(env, lclass, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
jclass
|
jclass
|
||||||
FindClass(JNIEnv* env, char* name) {
|
FindClass(JNIEnv* env, char* name) {
|
||||||
jstring strClassName = (*env)->NewStringUTF(env, name);
|
jstring strClassName = (*env)->NewStringUTF(env, name);
|
||||||
|
@ -36,6 +105,10 @@ void CallVoidMethod(JNIEnv *env, jobject obj, jmethodID methodID) {
|
||||||
(*env)->CallVoidMethod(env, obj, 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) {
|
jint CallIntMethod(JNIEnv *env, jobject obj, jmethodID methodID) {
|
||||||
return (*env)->CallIntMethod(env, obj, methodID);
|
return (*env)->CallIntMethod(env, obj, methodID);
|
||||||
}
|
}
|
||||||
|
@ -74,7 +147,7 @@ type JNIEnv = C.JNIEnv
|
||||||
func setJVM(jvm, context uintptr) {
|
func setJVM(jvm, context uintptr) {
|
||||||
log.Print("set theJVM")
|
log.Print("set theJVM")
|
||||||
theJVM = (*C.JavaVM)(unsafe.Pointer(jvm))
|
theJVM = (*C.JavaVM)(unsafe.Pointer(jvm))
|
||||||
log.Printf("theJVM = %d", uintptr(unsafe.Pointer(theJVM)))
|
//log.Printf("theJVM = %d", uintptr(unsafe.Pointer(theJVM)))
|
||||||
RunInJVM(func(env *C.JNIEnv) {
|
RunInJVM(func(env *C.JNIEnv) {
|
||||||
C.SetLoader(env, (C.jobject)(context))
|
C.SetLoader(env, (C.jobject)(context))
|
||||||
})
|
})
|
||||||
|
@ -86,10 +159,28 @@ func FindClass(env *C.JNIEnv, name string) C.jclass {
|
||||||
return C.FindClass((*C.JNIEnv)(env), 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) {
|
func JniCallVoidMethod(env *C.JNIEnv, obj C.jobject, methodID C.jmethodID) {
|
||||||
C.CallVoidMethod(env, obj, methodID)
|
C.CallVoidMethod(env, obj, methodID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func JniCallBooleanMethod(env *C.JNIEnv, obj C.jobject, methodID C.jmethodID) bool {
|
||||||
|
return C.CallBooleanMethod(env, obj, methodID) == 0
|
||||||
|
}
|
||||||
|
|
||||||
func JniCallIntMethod(env *C.JNIEnv, obj C.jobject, methodID C.jmethodID) int {
|
func JniCallIntMethod(env *C.JNIEnv, obj C.jobject, methodID C.jmethodID) int {
|
||||||
return (int)(C.CallIntMethod(env, obj, methodID))
|
return (int)(C.CallIntMethod(env, obj, methodID))
|
||||||
}
|
}
|
||||||
|
@ -111,7 +202,7 @@ func RunInJVM(f func(env *C.JNIEnv)) {
|
||||||
defer runtime.UnlockOSThread()
|
defer runtime.UnlockOSThread()
|
||||||
var env *C.JNIEnv
|
var env *C.JNIEnv
|
||||||
var detach bool
|
var detach bool
|
||||||
log.Printf("RunInJVM(): theJVM = %d", uintptr(unsafe.Pointer(theJVM)))
|
//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.GetEnv(theJVM, &env, C.JNI_VERSION_1_6); res != C.JNI_OK {
|
||||||
if res != C.JNI_EDETACHED {
|
if res != C.JNI_EDETACHED {
|
||||||
panic(fmt.Errorf("JNI GetEnv failed with error %d", res))
|
panic(fmt.Errorf("JNI GetEnv failed with error %d", res))
|
||||||
|
|
Loading…
Reference in New Issue
Block a user