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 1 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 34 namespace android { 35 36 static jmethodID method_onConnectStateChanged; 37 static jmethodID method_onGetProtocolMode; 38 static jmethodID method_onGetReport; 39 static jmethodID method_onHandshake; 40 static jmethodID method_onVirtualUnplug; 41 42 static const bthh_interface_t *sBluetoothHidInterface = NULL; 43 static jobject mCallbacksObj = NULL; 44 static JNIEnv *sCallbackEnv = NULL; 45 46 static bool checkCallbackThread() { 47 48 // Always fetch the latest callbackEnv from AdapterService. 49 // Caching this could cause this sCallbackEnv to go out-of-sync 50 // with the AdapterService's ENV if an ASSOCIATE/DISASSOCIATE event 51 // is received 52 53 sCallbackEnv = getCallbackEnv(); 54 55 JNIEnv* env = AndroidRuntime::getJNIEnv(); 56 if (sCallbackEnv != env || sCallbackEnv == NULL) return false; 57 return true; 58 } 59 60 static void connection_state_callback(bt_bdaddr_t *bd_addr, bthh_connection_state_t state) { 61 jbyteArray addr; 62 63 CHECK_CALLBACK_ENV 64 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 65 if (!addr) { 66 ALOGE("Fail to new jbyteArray bd addr for HID channel state"); 67 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 68 return; 69 } 70 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr); 71 72 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectStateChanged, addr, (jint) state); 73 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 74 sCallbackEnv->DeleteLocalRef(addr); 75 } 76 77 static void get_protocol_mode_callback(bt_bdaddr_t *bd_addr, bthh_status_t hh_status,bthh_protocol_mode_t mode) { 78 jbyteArray addr; 79 80 CHECK_CALLBACK_ENV 81 if (hh_status != BTHH_OK) { 82 ALOGE("BTHH Status is not OK!"); 83 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 84 return; 85 } 86 87 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 88 if (!addr) { 89 ALOGE("Fail to new jbyteArray bd addr for get protocal mode callback"); 90 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 91 return; 92 } 93 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr); 94 95 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetProtocolMode, addr, (jint) mode); 96 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 97 sCallbackEnv->DeleteLocalRef(addr); 98 } 99 100 static void get_report_callback(bt_bdaddr_t *bd_addr, bthh_status_t hh_status, uint8_t *rpt_data, int rpt_size) { 101 jbyteArray addr; 102 jbyteArray data; 103 104 CHECK_CALLBACK_ENV 105 if (hh_status != BTHH_OK) { 106 ALOGE("BTHH Status is not OK!"); 107 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 108 return; 109 } 110 111 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 112 if (!addr) { 113 ALOGE("Fail to new jbyteArray bd addr for get report callback"); 114 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 115 return; 116 } 117 data = sCallbackEnv->NewByteArray(rpt_size); 118 if (!data) { 119 ALOGE("Fail to new jbyteArray data for get report callback"); 120 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 121 sCallbackEnv->DeleteLocalRef(addr); 122 return; 123 } 124 125 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr); 126 sCallbackEnv->SetByteArrayRegion(data, 0, rpt_size, (jbyte *) rpt_data); 127 128 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetReport, addr, data, (jint) rpt_size); 129 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 130 sCallbackEnv->DeleteLocalRef(addr); 131 sCallbackEnv->DeleteLocalRef(data); 132 } 133 134 static void virtual_unplug_callback(bt_bdaddr_t *bd_addr, bthh_status_t hh_status) { 135 ALOGV("call to virtual_unplug_callback"); 136 jbyteArray addr; 137 138 CHECK_CALLBACK_ENV 139 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 140 if (!addr) { 141 ALOGE("Fail to new jbyteArray bd addr for HID channel state"); 142 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 143 return; 144 } 145 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr); 146 147 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVirtualUnplug, addr, (jint) hh_status); 148 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 149 sCallbackEnv->DeleteLocalRef(addr); 150 151 /*jbyteArray addr; 152 jint status = hh_status; 153 CHECK_CALLBACK_ENV 154 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 155 if (!addr) { 156 ALOGE("Fail to new jbyteArray bd addr for HID report"); 157 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 158 return; 159 } 160 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr); 161 162 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVirtualUnplug, addr, status); 163 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 164 sCallbackEnv->DeleteLocalRef(addr);*/ 165 } 166 167 static void handshake_callback(bt_bdaddr_t *bd_addr, bthh_status_t hh_status) 168 { 169 jbyteArray addr; 170 171 CHECK_CALLBACK_ENV 172 173 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 174 if (!addr) { 175 ALOGE("Fail to new jbyteArray bd addr for handshake callback"); 176 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 177 return; 178 } 179 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr); 180 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onHandshake, addr, (jint) hh_status); 181 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 182 sCallbackEnv->DeleteLocalRef(addr); 183 } 184 185 static bthh_callbacks_t sBluetoothHidCallbacks = { 186 sizeof(sBluetoothHidCallbacks), 187 connection_state_callback, 188 NULL, 189 get_protocol_mode_callback, 190 NULL, 191 get_report_callback, 192 virtual_unplug_callback, 193 handshake_callback 194 }; 195 196 // Define native functions 197 198 static void classInitNative(JNIEnv* env, jclass clazz) { 199 int err; 200 // const bt_interface_t* btInf; 201 // bt_status_t status; 202 203 method_onConnectStateChanged = env->GetMethodID(clazz, "onConnectStateChanged", "([BI)V"); 204 method_onGetProtocolMode = env->GetMethodID(clazz, "onGetProtocolMode", "([BI)V"); 205 method_onGetReport = env->GetMethodID(clazz, "onGetReport", "([B[BI)V"); 206 method_onHandshake = env->GetMethodID(clazz, "onHandshake", "([BI)V"); 207 method_onVirtualUnplug = env->GetMethodID(clazz, "onVirtualUnplug", "([BI)V"); 208 209 /* 210 if ( (btInf = getBluetoothInterface()) == NULL) { 211 ALOGE("Bluetooth module is not loaded"); 212 return; 213 } 214 215 if ( (sBluetoothHidInterface = (bthh_interface_t *) 216 btInf->get_profile_interface(BT_PROFILE_HIDHOST_ID)) == NULL) { 217 ALOGE("Failed to get Bluetooth Handsfree Interface"); 218 return; 219 } 220 221 // TODO(BT) do this only once or 222 // Do we need to do this every time the BT reenables? 223 if ( (status = sBluetoothHidInterface->init(&sBluetoothHidCallbacks)) != BT_STATUS_SUCCESS) { 224 ALOGE("Failed to initialize Bluetooth HID, status: %d", status); 225 sBluetoothHidInterface = NULL; 226 return; 227 } 228 229 */ 230 ALOGI("%s: succeeds", __FUNCTION__); 231 } 232 233 static void initializeNative(JNIEnv *env, jobject object) { 234 const bt_interface_t* btInf; 235 bt_status_t status; 236 237 if ( (btInf = getBluetoothInterface()) == NULL) { 238 ALOGE("Bluetooth module is not loaded"); 239 return; 240 } 241 242 if (sBluetoothHidInterface !=NULL) { 243 ALOGW("Cleaning up Bluetooth HID Interface before initializing..."); 244 sBluetoothHidInterface->cleanup(); 245 sBluetoothHidInterface = NULL; 246 } 247 248 if (mCallbacksObj != NULL) { 249 ALOGW("Cleaning up Bluetooth GID callback object"); 250 env->DeleteGlobalRef(mCallbacksObj); 251 mCallbacksObj = NULL; 252 } 253 254 255 if ( (sBluetoothHidInterface = (bthh_interface_t *) 256 btInf->get_profile_interface(BT_PROFILE_HIDHOST_ID)) == NULL) { 257 ALOGE("Failed to get Bluetooth HID Interface"); 258 return; 259 } 260 261 if ( (status = sBluetoothHidInterface->init(&sBluetoothHidCallbacks)) != BT_STATUS_SUCCESS) { 262 ALOGE("Failed to initialize Bluetooth HID, status: %d", status); 263 sBluetoothHidInterface = NULL; 264 return; 265 } 266 267 268 269 mCallbacksObj = env->NewGlobalRef(object); 270 } 271 272 static void cleanupNative(JNIEnv *env, jobject object) { 273 const bt_interface_t* btInf; 274 bt_status_t status; 275 276 if ( (btInf = getBluetoothInterface()) == NULL) { 277 ALOGE("Bluetooth module is not loaded"); 278 return; 279 } 280 281 if (sBluetoothHidInterface !=NULL) { 282 ALOGW("Cleaning up Bluetooth HID Interface..."); 283 sBluetoothHidInterface->cleanup(); 284 sBluetoothHidInterface = NULL; 285 } 286 287 if (mCallbacksObj != NULL) { 288 ALOGW("Cleaning up Bluetooth GID callback object"); 289 env->DeleteGlobalRef(mCallbacksObj); 290 mCallbacksObj = NULL; 291 } 292 293 env->DeleteGlobalRef(mCallbacksObj); 294 } 295 296 static jboolean connectHidNative(JNIEnv *env, jobject object, jbyteArray address) { 297 bt_status_t status; 298 jbyte *addr; 299 jboolean ret = JNI_TRUE; 300 if (!sBluetoothHidInterface) return JNI_FALSE; 301 302 addr = env->GetByteArrayElements(address, NULL); 303 if (!addr) { 304 ALOGE("Bluetooth device address null"); 305 return JNI_FALSE; 306 } 307 308 if ((status = sBluetoothHidInterface->connect((bt_bdaddr_t *) addr)) != 309 BT_STATUS_SUCCESS) { 310 ALOGE("Failed HID channel connection, status: %d", status); 311 ret = JNI_FALSE; 312 } 313 env->ReleaseByteArrayElements(address, addr, 0); 314 315 return ret; 316 } 317 318 static jboolean disconnectHidNative(JNIEnv *env, jobject object, jbyteArray address) { 319 bt_status_t status; 320 jbyte *addr; 321 jboolean ret = JNI_TRUE; 322 if (!sBluetoothHidInterface) return JNI_FALSE; 323 324 addr = env->GetByteArrayElements(address, NULL); 325 if (!addr) { 326 ALOGE("Bluetooth device address null"); 327 return JNI_FALSE; 328 } 329 330 if ( (status = sBluetoothHidInterface->disconnect((bt_bdaddr_t *) addr)) != 331 BT_STATUS_SUCCESS) { 332 ALOGE("Failed disconnect hid channel, status: %d", status); 333 ret = JNI_FALSE; 334 } 335 env->ReleaseByteArrayElements(address, addr, 0); 336 337 return ret; 338 } 339 340 static jboolean getProtocolModeNative(JNIEnv *env, jobject object, jbyteArray address) { 341 bt_status_t status; 342 jbyte *addr; 343 jboolean ret = JNI_TRUE; 344 bthh_protocol_mode_t protocolMode; 345 if (!sBluetoothHidInterface) return JNI_FALSE; 346 347 addr = env->GetByteArrayElements(address, NULL); 348 if (!addr) { 349 ALOGE("Bluetooth device address null"); 350 return JNI_FALSE; 351 } 352 353 if ( (status = sBluetoothHidInterface->get_protocol((bt_bdaddr_t *) addr, (bthh_protocol_mode_t) protocolMode)) != 354 BT_STATUS_SUCCESS) { 355 ALOGE("Failed get protocol mode, status: %d", status); 356 ret = JNI_FALSE; 357 } 358 env->ReleaseByteArrayElements(address, addr, 0); 359 360 return ret; 361 } 362 363 static jboolean virtualUnPlugNative(JNIEnv *env, jobject object, jbyteArray address) { 364 bt_status_t status; 365 jbyte *addr; 366 jboolean ret = JNI_TRUE; 367 if (!sBluetoothHidInterface) return JNI_FALSE; 368 369 addr = env->GetByteArrayElements(address, NULL); 370 if (!addr) { 371 ALOGE("Bluetooth device address null"); 372 return JNI_FALSE; 373 } 374 if ( (status = sBluetoothHidInterface->virtual_unplug((bt_bdaddr_t *) addr)) != 375 BT_STATUS_SUCCESS) { 376 ALOGE("Failed virual unplug, status: %d", status); 377 ret = JNI_FALSE; 378 } 379 env->ReleaseByteArrayElements(address, addr, 0); 380 return ret; 381 382 } 383 384 385 static jboolean setProtocolModeNative(JNIEnv *env, jobject object, jbyteArray address, jint protocolMode) { 386 bt_status_t status; 387 jbyte *addr; 388 jboolean ret = JNI_TRUE; 389 if (!sBluetoothHidInterface) return JNI_FALSE; 390 391 ALOGD("%s: protocolMode = %d", __FUNCTION__, protocolMode); 392 393 addr = env->GetByteArrayElements(address, NULL); 394 if (!addr) { 395 ALOGE("Bluetooth device address null"); 396 return JNI_FALSE; 397 } 398 399 bthh_protocol_mode_t mode; 400 switch(protocolMode){ 401 case 0: 402 mode = BTHH_REPORT_MODE; 403 break; 404 case 1: 405 mode = BTHH_BOOT_MODE; 406 break; 407 default: 408 ALOGE("Unknown HID protocol mode"); 409 return JNI_FALSE; 410 } 411 if ( (status = sBluetoothHidInterface->set_protocol((bt_bdaddr_t *) addr, mode)) != 412 BT_STATUS_SUCCESS) { 413 ALOGE("Failed set protocol mode, status: %d", status); 414 ret = JNI_FALSE; 415 } 416 env->ReleaseByteArrayElements(address, addr, 0); 417 418 return JNI_TRUE; 419 } 420 421 static jboolean getReportNative(JNIEnv *env, jobject object, jbyteArray address, jbyte reportType, jbyte reportId, jint bufferSize) { 422 ALOGV("%s: reportType = %d, reportId = %d, bufferSize = %d", __FUNCTION__, reportType, reportId, bufferSize); 423 424 bt_status_t status; 425 jbyte *addr; 426 jboolean ret = JNI_TRUE; 427 if (!sBluetoothHidInterface) return JNI_FALSE; 428 429 addr = env->GetByteArrayElements(address, NULL); 430 if (!addr) { 431 ALOGE("Bluetooth device address null"); 432 return JNI_FALSE; 433 } 434 435 jint rType = reportType; 436 jint rId = reportId; 437 438 if ( (status = sBluetoothHidInterface->get_report((bt_bdaddr_t *) addr, (bthh_report_type_t) rType, (uint8_t) rId, bufferSize)) != 439 BT_STATUS_SUCCESS) { 440 ALOGE("Failed get report, status: %d", status); 441 ret = JNI_FALSE; 442 } 443 env->ReleaseByteArrayElements(address, addr, 0); 444 445 return ret; 446 } 447 448 449 static jboolean setReportNative(JNIEnv *env, jobject object, jbyteArray address, jbyte reportType, jstring report) { 450 ALOGV("%s: reportType = %d", __FUNCTION__, reportType); 451 bt_status_t status; 452 jbyte *addr; 453 jboolean ret = JNI_TRUE; 454 if (!sBluetoothHidInterface) return JNI_FALSE; 455 456 addr = env->GetByteArrayElements(address, NULL); 457 if (!addr) { 458 ALOGE("Bluetooth device address null"); 459 return JNI_FALSE; 460 } 461 jint rType = reportType; 462 const char *c_report = env->GetStringUTFChars(report, NULL); 463 464 if ( (status = sBluetoothHidInterface->set_report((bt_bdaddr_t *) addr, (bthh_report_type_t)rType, (char*) c_report)) != 465 BT_STATUS_SUCCESS) { 466 ALOGE("Failed set report, status: %d", status); 467 ret = JNI_FALSE; 468 } 469 env->ReleaseStringUTFChars(report, c_report); 470 env->ReleaseByteArrayElements(address, addr, 0); 471 472 return ret; 473 } 474 475 static jboolean sendDataNative(JNIEnv *env, jobject object, jbyteArray address, jstring report) { 476 ALOGV("%s", __FUNCTION__); 477 bt_status_t status; 478 jbyte *addr; 479 jboolean ret = JNI_TRUE; 480 if (!sBluetoothHidInterface) return JNI_FALSE; 481 482 addr = env->GetByteArrayElements(address, NULL); 483 if (!addr) { 484 ALOGE("Bluetooth device address null"); 485 return JNI_FALSE; 486 } 487 const char *c_report = env->GetStringUTFChars(report, NULL); 488 if ( (status = sBluetoothHidInterface->send_data((bt_bdaddr_t *) addr, (char*) c_report)) != 489 BT_STATUS_SUCCESS) { 490 ALOGE("Failed set report, status: %d", status); 491 ret = JNI_FALSE; 492 } 493 env->ReleaseStringUTFChars(report, c_report); 494 env->ReleaseByteArrayElements(address, addr, 0); 495 496 return ret; 497 498 } 499 500 static JNINativeMethod sMethods[] = { 501 {"classInitNative", "()V", (void *) classInitNative}, 502 {"initializeNative", "()V", (void *) initializeNative}, 503 {"cleanupNative", "()V", (void *) cleanupNative}, 504 {"connectHidNative", "([B)Z", (void *) connectHidNative}, 505 {"disconnectHidNative", "([B)Z", (void *) disconnectHidNative}, 506 {"getProtocolModeNative", "([B)Z", (void *) getProtocolModeNative}, 507 {"virtualUnPlugNative", "([B)Z", (void *) virtualUnPlugNative}, 508 {"setProtocolModeNative", "([BB)Z", (void *) setProtocolModeNative}, 509 {"getReportNative", "([BBBI)Z", (void *) getReportNative}, 510 {"setReportNative", "([BBLjava/lang/String;)Z", (void *) setReportNative}, 511 {"sendDataNative", "([BLjava/lang/String;)Z", (void *) sendDataNative}, 512 }; 513 514 int register_com_android_bluetooth_hid(JNIEnv* env) 515 { 516 return jniRegisterNativeMethods(env, "com/android/bluetooth/hid/HidService", 517 sMethods, NELEM(sMethods)); 518 } 519 520 } 521