com_android_bluetooth_hid.cpp revision 89d2a16ff98d1b6254139e1589404161d5c419c7
1/* 2 * Copyright (C) 2012 Google Inc. 3 */ 4 5#define LOG_TAG "BluetoothHidServiceJni" 6 7#define LOG_NDEBUG 0 8 9#define CHECK_CALLBACK_ENV \ 10 if (!checkCallbackThread()) { \ 11 LOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);\ 12 return; \ 13 } 14 15#include "com_android_bluetooth.h" 16#include "hardware/bt_hh.h" 17#include "utils/Log.h" 18#include "android_runtime/AndroidRuntime.h" 19 20#include <string.h> 21 22namespace android { 23 24static jmethodID method_onConnectStateChanged; 25 26static const bthh_interface_t *sBluetoothHidInterface = NULL; 27static jobject mCallbacksObj = NULL; 28static JNIEnv *sCallbackEnv = NULL; 29 30static bool checkCallbackThread() { 31 32 // Always fetch the latest callbackEnv from AdapterService. 33 // Caching this could cause this sCallbackEnv to go out-of-sync 34 // with the AdapterService's ENV if an ASSOCIATE/DISASSOCIATE event 35 // is received 36 37 sCallbackEnv = getCallbackEnv(); 38 39 JNIEnv* env = AndroidRuntime::getJNIEnv(); 40 if (sCallbackEnv != env || sCallbackEnv == NULL) return false; 41 return true; 42} 43 44static void connection_state_callback(bt_bdaddr_t *bd_addr, bthh_connection_state_t state) { 45 jbyteArray addr; 46 47 CHECK_CALLBACK_ENV 48 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 49 if (!addr) { 50 LOGE("Fail to new jbyteArray bd addr for HID channel state"); 51 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 52 return; 53 } 54 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr); 55 56 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectStateChanged, addr, (jint) state); 57 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 58 sCallbackEnv->DeleteLocalRef(addr); 59} 60 61static bthh_callbacks_t sBluetoothHidCallbacks = { 62 sizeof(sBluetoothHidCallbacks), 63 connection_state_callback, 64 NULL, 65 NULL, 66 NULL, 67 NULL, 68 NULL 69}; 70 71// Define native functions 72 73static void classInitNative(JNIEnv* env, jclass clazz) { 74 int err; 75 const bt_interface_t* btInf; 76 bt_status_t status; 77 78 method_onConnectStateChanged = env->GetMethodID(clazz, "onConnectStateChanged", 79 "([BI)V"); 80 81 if ( (btInf = getBluetoothInterface()) == NULL) { 82 LOGE("Bluetooth module is not loaded"); 83 return; 84 } 85 86 if ( (sBluetoothHidInterface = (bthh_interface_t *) 87 btInf->get_profile_interface(BT_PROFILE_HIDHOST_ID)) == NULL) { 88 LOGE("Failed to get Bluetooth Handsfree Interface"); 89 return; 90 } 91 92 // TODO(BT) do this only once or 93 // Do we need to do this every time the BT reenables? 94 if ( (status = sBluetoothHidInterface->init(&sBluetoothHidCallbacks)) != BT_STATUS_SUCCESS) { 95 LOGE("Failed to initialize Bluetooth HID, status: %d", status); 96 sBluetoothHidInterface = NULL; 97 return; 98 } 99 100 LOGI("%s: succeeds", __FUNCTION__); 101} 102 103static void initializeNativeDataNative(JNIEnv *env, jobject object) { 104 // TODO(BT) clean it up when hid service is stopped 105 mCallbacksObj = env->NewGlobalRef(object); 106} 107 108static jboolean connectHidNative(JNIEnv *env, jobject object, jbyteArray address) { 109 bt_status_t status; 110 jbyte *addr; 111 jboolean ret = JNI_TRUE; 112 if (!sBluetoothHidInterface) return JNI_FALSE; 113 114 addr = env->GetByteArrayElements(address, NULL); 115 if (!addr) { 116 LOGE("Bluetooth device address null"); 117 return JNI_FALSE; 118 } 119 120 if ((status = sBluetoothHidInterface->connect((bt_bdaddr_t *) addr)) != 121 BT_STATUS_SUCCESS) { 122 LOGE("Failed HID channel connection, status: %d", status); 123 ret = JNI_FALSE; 124 } 125 env->ReleaseByteArrayElements(address, addr, 0); 126 127 return ret; 128} 129 130static jboolean disconnectHidNative(JNIEnv *env, jobject object, jbyteArray address) { 131 bt_status_t status; 132 jbyte *addr; 133 jboolean ret = JNI_TRUE; 134 if (!sBluetoothHidInterface) return JNI_FALSE; 135 136 addr = env->GetByteArrayElements(address, NULL); 137 if (!addr) { 138 LOGE("Bluetooth device address null"); 139 return JNI_FALSE; 140 } 141 142 if ( (status = sBluetoothHidInterface->disconnect((bt_bdaddr_t *) addr)) != 143 BT_STATUS_SUCCESS) { 144 LOGE("Failed disconnect hid channel, status: %d", status); 145 ret = JNI_FALSE; 146 } 147 env->ReleaseByteArrayElements(address, addr, 0); 148 149 return ret; 150} 151 152static JNINativeMethod sMethods[] = { 153 {"classInitNative", "()V", (void *) classInitNative}, 154 {"initializeNativeDataNative", "()V", (void *) initializeNativeDataNative}, 155 {"connectHidNative", "([B)Z", (void *) connectHidNative}, 156 {"disconnectHidNative", "([B)Z", (void *) disconnectHidNative}, 157 // TBD 158}; 159 160int register_com_android_bluetooth_hid(JNIEnv* env) 161{ 162 return jniRegisterNativeMethods(env, "com/android/bluetooth/hid/HidService", 163 sMethods, NELEM(sMethods)); 164} 165 166} 167