com_android_bluetooth_hid.cpp revision ede67c26e7b2564ea35db6d9b3027a269c150e13
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define LOG_TAG "BluetoothHidServiceJni" 18 19#define LOG_NDEBUG 0 20 21#define CHECK_CALLBACK_ENV \ 22 if (!checkCallbackThread()) { \ 23 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);\ 24 return; \ 25 } 26 27#include "com_android_bluetooth.h" 28#include "hardware/bt_hh.h" 29#include "utils/Log.h" 30#include "android_runtime/AndroidRuntime.h" 31 32#include <string.h> 33 34namespace android { 35 36static jmethodID method_onConnectStateChanged; 37static jmethodID method_onGetProtocolMode; 38static jmethodID method_onGetReport; 39static jmethodID method_onVirtualUnplug; 40 41static const bthh_interface_t *sBluetoothHidInterface = NULL; 42static jobject mCallbacksObj = NULL; 43static JNIEnv *sCallbackEnv = NULL; 44 45static bool checkCallbackThread() { 46 47 // Always fetch the latest callbackEnv from AdapterService. 48 // Caching this could cause this sCallbackEnv to go out-of-sync 49 // with the AdapterService's ENV if an ASSOCIATE/DISASSOCIATE event 50 // is received 51 52 sCallbackEnv = getCallbackEnv(); 53 54 JNIEnv* env = AndroidRuntime::getJNIEnv(); 55 if (sCallbackEnv != env || sCallbackEnv == NULL) return false; 56 return true; 57} 58 59static void connection_state_callback(bt_bdaddr_t *bd_addr, bthh_connection_state_t state) { 60 jbyteArray addr; 61 62 CHECK_CALLBACK_ENV 63 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 64 if (!addr) { 65 ALOGE("Fail to new jbyteArray bd addr for HID channel state"); 66 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 67 return; 68 } 69 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr); 70 71 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectStateChanged, addr, (jint) state); 72 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 73 sCallbackEnv->DeleteLocalRef(addr); 74} 75 76static void get_protocol_mode_callback(bt_bdaddr_t *bd_addr, bthh_status_t hh_status,bthh_protocol_mode_t mode) { 77 jbyteArray addr; 78 79 CHECK_CALLBACK_ENV 80 if (hh_status != BTHH_OK) { 81 ALOGE("BTHH Status is not OK!"); 82 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 83 return; 84 } 85 86 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 87 if (!addr) { 88 ALOGE("Fail to new jbyteArray bd addr for get protocal mode callback"); 89 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 90 return; 91 } 92 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr); 93 94 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetProtocolMode, addr, (jint) mode); 95 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 96 sCallbackEnv->DeleteLocalRef(addr); 97} 98 99static void virtual_unplug_callback(bt_bdaddr_t *bd_addr, bthh_status_t hh_status) { 100 ALOGD("call to virtual_unplug_callback"); 101 jbyteArray addr; 102 103 CHECK_CALLBACK_ENV 104 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 105 if (!addr) { 106 ALOGE("Fail to new jbyteArray bd addr for HID channel state"); 107 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 108 return; 109 } 110 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr); 111 112 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVirtualUnplug, addr, (jint) hh_status); 113 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 114 sCallbackEnv->DeleteLocalRef(addr); 115 116 /*jbyteArray addr; 117 jint status = hh_status; 118 CHECK_CALLBACK_ENV 119 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 120 if (!addr) { 121 ALOGE("Fail to new jbyteArray bd addr for HID report"); 122 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 123 return; 124 } 125 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr); 126 127 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVirtualUnplug, addr, status); 128 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 129 sCallbackEnv->DeleteLocalRef(addr);*/ 130} 131 132 133static bthh_callbacks_t sBluetoothHidCallbacks = { 134 sizeof(sBluetoothHidCallbacks), 135 connection_state_callback, 136 NULL, 137 get_protocol_mode_callback, 138 NULL, 139 NULL, 140 virtual_unplug_callback 141}; 142 143// Define native functions 144 145static void classInitNative(JNIEnv* env, jclass clazz) { 146 int err; 147// const bt_interface_t* btInf; 148// bt_status_t status; 149 150 method_onConnectStateChanged = env->GetMethodID(clazz, "onConnectStateChanged", "([BI)V"); 151 method_onGetProtocolMode = env->GetMethodID(clazz, "onGetProtocolMode", "([BI)V"); 152 method_onVirtualUnplug = env->GetMethodID(clazz, "onVirtualUnplug", "([BI)V"); 153 154/* 155 if ( (btInf = getBluetoothInterface()) == NULL) { 156 ALOGE("Bluetooth module is not loaded"); 157 return; 158 } 159 160 if ( (sBluetoothHidInterface = (bthh_interface_t *) 161 btInf->get_profile_interface(BT_PROFILE_HIDHOST_ID)) == NULL) { 162 ALOGE("Failed to get Bluetooth Handsfree Interface"); 163 return; 164 } 165 166 // TODO(BT) do this only once or 167 // Do we need to do this every time the BT reenables? 168 if ( (status = sBluetoothHidInterface->init(&sBluetoothHidCallbacks)) != BT_STATUS_SUCCESS) { 169 ALOGE("Failed to initialize Bluetooth HID, status: %d", status); 170 sBluetoothHidInterface = NULL; 171 return; 172 } 173 174*/ 175 ALOGI("%s: succeeds", __FUNCTION__); 176} 177 178static void initializeNative(JNIEnv *env, jobject object) { 179 const bt_interface_t* btInf; 180 bt_status_t status; 181 182 if ( (btInf = getBluetoothInterface()) == NULL) { 183 ALOGE("Bluetooth module is not loaded"); 184 return; 185 } 186 187 if (sBluetoothHidInterface !=NULL) { 188 ALOGW("Cleaning up Bluetooth HID Interface before initializing..."); 189 sBluetoothHidInterface->cleanup(); 190 sBluetoothHidInterface = NULL; 191 } 192 193 if (mCallbacksObj != NULL) { 194 ALOGW("Cleaning up Bluetooth GID callback object"); 195 env->DeleteGlobalRef(mCallbacksObj); 196 mCallbacksObj = NULL; 197 } 198 199 200 if ( (sBluetoothHidInterface = (bthh_interface_t *) 201 btInf->get_profile_interface(BT_PROFILE_HIDHOST_ID)) == NULL) { 202 ALOGE("Failed to get Bluetooth HID Interface"); 203 return; 204 } 205 206 if ( (status = sBluetoothHidInterface->init(&sBluetoothHidCallbacks)) != BT_STATUS_SUCCESS) { 207 ALOGE("Failed to initialize Bluetooth HID, status: %d", status); 208 sBluetoothHidInterface = NULL; 209 return; 210 } 211 212 213 214 mCallbacksObj = env->NewGlobalRef(object); 215} 216 217static void cleanupNative(JNIEnv *env, jobject object) { 218 const bt_interface_t* btInf; 219 bt_status_t status; 220 221 if ( (btInf = getBluetoothInterface()) == NULL) { 222 ALOGE("Bluetooth module is not loaded"); 223 return; 224 } 225 226 if (sBluetoothHidInterface !=NULL) { 227 ALOGW("Cleaning up Bluetooth HID Interface..."); 228 sBluetoothHidInterface->cleanup(); 229 sBluetoothHidInterface = NULL; 230 } 231 232 if (mCallbacksObj != NULL) { 233 ALOGW("Cleaning up Bluetooth GID callback object"); 234 env->DeleteGlobalRef(mCallbacksObj); 235 mCallbacksObj = NULL; 236 } 237 238 env->DeleteGlobalRef(mCallbacksObj); 239} 240 241static jboolean connectHidNative(JNIEnv *env, jobject object, jbyteArray address) { 242 bt_status_t status; 243 jbyte *addr; 244 jboolean ret = JNI_TRUE; 245 if (!sBluetoothHidInterface) return JNI_FALSE; 246 247 addr = env->GetByteArrayElements(address, NULL); 248 if (!addr) { 249 ALOGE("Bluetooth device address null"); 250 return JNI_FALSE; 251 } 252 253 if ((status = sBluetoothHidInterface->connect((bt_bdaddr_t *) addr)) != 254 BT_STATUS_SUCCESS) { 255 ALOGE("Failed HID channel connection, status: %d", status); 256 ret = JNI_FALSE; 257 } 258 env->ReleaseByteArrayElements(address, addr, 0); 259 260 return ret; 261} 262 263static jboolean disconnectHidNative(JNIEnv *env, jobject object, jbyteArray address) { 264 bt_status_t status; 265 jbyte *addr; 266 jboolean ret = JNI_TRUE; 267 if (!sBluetoothHidInterface) return JNI_FALSE; 268 269 addr = env->GetByteArrayElements(address, NULL); 270 if (!addr) { 271 ALOGE("Bluetooth device address null"); 272 return JNI_FALSE; 273 } 274 275 if ( (status = sBluetoothHidInterface->disconnect((bt_bdaddr_t *) addr)) != 276 BT_STATUS_SUCCESS) { 277 ALOGE("Failed disconnect hid channel, status: %d", status); 278 ret = JNI_FALSE; 279 } 280 env->ReleaseByteArrayElements(address, addr, 0); 281 282 return ret; 283} 284 285static jboolean getProtocolModeNative(JNIEnv *env, jobject object, jbyteArray address) { 286 bt_status_t status; 287 jbyte *addr; 288 jboolean ret = JNI_TRUE; 289 bthh_protocol_mode_t protocolMode; 290 if (!sBluetoothHidInterface) return JNI_FALSE; 291 292 addr = env->GetByteArrayElements(address, NULL); 293 if (!addr) { 294 ALOGE("Bluetooth device address null"); 295 return JNI_FALSE; 296 } 297 298 if ( (status = sBluetoothHidInterface->get_protocol((bt_bdaddr_t *) addr, (bthh_protocol_mode_t) protocolMode)) != 299 BT_STATUS_SUCCESS) { 300 ALOGE("Failed get protocol mode, status: %d", status); 301 ret = JNI_FALSE; 302 } 303 env->ReleaseByteArrayElements(address, addr, 0); 304 305 return ret; 306} 307 308static jboolean virtualUnPlugNative(JNIEnv *env, jobject object, jbyteArray address) { 309 bt_status_t status; 310 jbyte *addr; 311 jboolean ret = JNI_TRUE; 312 if (!sBluetoothHidInterface) return JNI_FALSE; 313 314 addr = env->GetByteArrayElements(address, NULL); 315 if (!addr) { 316 ALOGE("Bluetooth device address null"); 317 return JNI_FALSE; 318 } 319 if ( (status = sBluetoothHidInterface->virtual_unplug((bt_bdaddr_t *) addr)) != 320 BT_STATUS_SUCCESS) { 321 ALOGE("Failed virual unplug, status: %d", status); 322 ret = JNI_FALSE; 323 } 324 env->ReleaseByteArrayElements(address, addr, 0); 325 return ret; 326 327} 328 329 330static jboolean setProtocolModeNative(JNIEnv *env, jobject object, jbyteArray address, jint protocolMode) { 331 bt_status_t status; 332 jbyte *addr; 333 jboolean ret = JNI_TRUE; 334 if (!sBluetoothHidInterface) return JNI_FALSE; 335 336 ALOGD("%s: protocolMode = %d", __FUNCTION__, protocolMode); 337 338 addr = env->GetByteArrayElements(address, NULL); 339 if (!addr) { 340 ALOGE("Bluetooth device address null"); 341 return JNI_FALSE; 342 } 343 344 bthh_protocol_mode_t mode; 345 switch(protocolMode){ 346 case 0: 347 mode = BTHH_REPORT_MODE; 348 break; 349 case 1: 350 mode = BTHH_BOOT_MODE; 351 break; 352 default: 353 ALOGE("Unknown HID protocol mode"); 354 return JNI_FALSE; 355 } 356 if ( (status = sBluetoothHidInterface->set_protocol((bt_bdaddr_t *) addr, mode)) != 357 BT_STATUS_SUCCESS) { 358 ALOGE("Failed set protocol mode, status: %d", status); 359 ret = JNI_FALSE; 360 } 361 env->ReleaseByteArrayElements(address, addr, 0); 362 363 return JNI_TRUE; 364} 365 366static jboolean getReportNative(JNIEnv *env, jobject object, jbyteArray address, jbyte reportType, jbyte reportId, jint bufferSize) { 367 ALOGD("%s: reportType = %d, reportId = %d, bufferSize = %d", __FUNCTION__, reportType, reportId, bufferSize); 368 369 bt_status_t status; 370 jbyte *addr; 371 jboolean ret = JNI_TRUE; 372 if (!sBluetoothHidInterface) return JNI_FALSE; 373 374 addr = env->GetByteArrayElements(address, NULL); 375 if (!addr) { 376 ALOGE("Bluetooth device address null"); 377 return JNI_FALSE; 378 } 379 380 jint rType = reportType; 381 jint rId = reportId; 382 383 if ( (status = sBluetoothHidInterface->get_report((bt_bdaddr_t *) addr, (bthh_report_type_t) rType, (uint8_t) rId, bufferSize)) != 384 BT_STATUS_SUCCESS) { 385 ALOGE("Failed get report, status: %d", status); 386 ret = JNI_FALSE; 387 } 388 env->ReleaseByteArrayElements(address, addr, 0); 389 390 return ret; 391} 392 393 394static jboolean setReportNative(JNIEnv *env, jobject object, jbyteArray address, jbyte reportType, jstring report) { 395 ALOGD("%s: reportType = %d", __FUNCTION__, reportType); 396 bt_status_t status; 397 jbyte *addr; 398 jboolean ret = JNI_TRUE; 399 if (!sBluetoothHidInterface) return JNI_FALSE; 400 401 addr = env->GetByteArrayElements(address, NULL); 402 if (!addr) { 403 ALOGE("Bluetooth device address null"); 404 return JNI_FALSE; 405 } 406 jint rType = reportType; 407 const char *c_report = env->GetStringUTFChars(report, NULL); 408 409 if ( (status = sBluetoothHidInterface->set_report((bt_bdaddr_t *) addr, (bthh_report_type_t)rType, (char*) c_report)) != 410 BT_STATUS_SUCCESS) { 411 ALOGE("Failed set report, status: %d", status); 412 ret = JNI_FALSE; 413 } 414 env->ReleaseStringUTFChars(report, c_report); 415 env->ReleaseByteArrayElements(address, addr, 0); 416 417 return ret; 418} 419 420static jboolean sendDataNative(JNIEnv *env, jobject object, jbyteArray address, jstring report) { 421 ALOGD("%s", __FUNCTION__); 422 bt_status_t status; 423 jbyte *addr; 424 jboolean ret = JNI_TRUE; 425 if (!sBluetoothHidInterface) return JNI_FALSE; 426 427 addr = env->GetByteArrayElements(address, NULL); 428 if (!addr) { 429 ALOGE("Bluetooth device address null"); 430 return JNI_FALSE; 431 } 432 const char *c_report = env->GetStringUTFChars(report, NULL); 433 if ( (status = sBluetoothHidInterface->send_data((bt_bdaddr_t *) addr, (char*) c_report)) != 434 BT_STATUS_SUCCESS) { 435 ALOGE("Failed set report, status: %d", status); 436 ret = JNI_FALSE; 437 } 438 env->ReleaseStringUTFChars(report, c_report); 439 env->ReleaseByteArrayElements(address, addr, 0); 440 441 return ret; 442 443} 444 445static JNINativeMethod sMethods[] = { 446 {"classInitNative", "()V", (void *) classInitNative}, 447 {"initializeNative", "()V", (void *) initializeNative}, 448 {"cleanupNative", "()V", (void *) cleanupNative}, 449 {"connectHidNative", "([B)Z", (void *) connectHidNative}, 450 {"disconnectHidNative", "([B)Z", (void *) disconnectHidNative}, 451 {"getProtocolModeNative", "([B)Z", (void *) getProtocolModeNative}, 452 {"virtualUnPlugNative", "([B)Z", (void *) virtualUnPlugNative}, 453 {"setProtocolModeNative", "([BB)Z", (void *) setProtocolModeNative}, 454 {"getReportNative", "([BBBI)Z", (void *) getReportNative}, 455 {"setReportNative", "([BBLjava/lang/String;)Z", (void *) setReportNative}, 456 {"sendDataNative", "([BLjava/lang/String;)Z", (void *) sendDataNative}, 457}; 458 459int register_com_android_bluetooth_hid(JNIEnv* env) 460{ 461 return jniRegisterNativeMethods(env, "com/android/bluetooth/hid/HidService", 462 sMethods, NELEM(sMethods)); 463} 464 465} 466