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 34namespace android { 35 36static jmethodID method_onConnectStateChanged; 37static jmethodID method_onGetProtocolMode; 38static jmethodID method_onGetReport; 39static jmethodID method_onHandshake; 40static jmethodID method_onVirtualUnplug; 41 42static const bthh_interface_t *sBluetoothHidInterface = NULL; 43static jobject mCallbacksObj = NULL; 44static JNIEnv *sCallbackEnv = NULL; 45 46static 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 60static 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 77static 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 100static 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 134static 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 167static 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 185static 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 198static void classInitNative(JNIEnv* env, jclass clazz) { 199 method_onConnectStateChanged = env->GetMethodID(clazz, "onConnectStateChanged", "([BI)V"); 200 method_onGetProtocolMode = env->GetMethodID(clazz, "onGetProtocolMode", "([BI)V"); 201 method_onGetReport = env->GetMethodID(clazz, "onGetReport", "([B[BI)V"); 202 method_onHandshake = env->GetMethodID(clazz, "onHandshake", "([BI)V"); 203 method_onVirtualUnplug = env->GetMethodID(clazz, "onVirtualUnplug", "([BI)V"); 204 205 ALOGI("%s: succeeds", __FUNCTION__); 206} 207 208static void initializeNative(JNIEnv *env, jobject object) { 209 const bt_interface_t* btInf; 210 bt_status_t status; 211 212 if ( (btInf = getBluetoothInterface()) == NULL) { 213 ALOGE("Bluetooth module is not loaded"); 214 return; 215 } 216 217 if (sBluetoothHidInterface !=NULL) { 218 ALOGW("Cleaning up Bluetooth HID Interface before initializing..."); 219 sBluetoothHidInterface->cleanup(); 220 sBluetoothHidInterface = NULL; 221 } 222 223 if (mCallbacksObj != NULL) { 224 ALOGW("Cleaning up Bluetooth GID callback object"); 225 env->DeleteGlobalRef(mCallbacksObj); 226 mCallbacksObj = NULL; 227 } 228 229 230 if ( (sBluetoothHidInterface = (bthh_interface_t *) 231 btInf->get_profile_interface(BT_PROFILE_HIDHOST_ID)) == NULL) { 232 ALOGE("Failed to get Bluetooth HID Interface"); 233 return; 234 } 235 236 if ( (status = sBluetoothHidInterface->init(&sBluetoothHidCallbacks)) != BT_STATUS_SUCCESS) { 237 ALOGE("Failed to initialize Bluetooth HID, status: %d", status); 238 sBluetoothHidInterface = NULL; 239 return; 240 } 241 242 243 244 mCallbacksObj = env->NewGlobalRef(object); 245} 246 247static void cleanupNative(JNIEnv *env, jobject object) { 248 const bt_interface_t* btInf; 249 250 if ( (btInf = getBluetoothInterface()) == NULL) { 251 ALOGE("Bluetooth module is not loaded"); 252 return; 253 } 254 255 if (sBluetoothHidInterface !=NULL) { 256 ALOGW("Cleaning up Bluetooth HID Interface..."); 257 sBluetoothHidInterface->cleanup(); 258 sBluetoothHidInterface = NULL; 259 } 260 261 if (mCallbacksObj != NULL) { 262 ALOGW("Cleaning up Bluetooth GID callback object"); 263 env->DeleteGlobalRef(mCallbacksObj); 264 mCallbacksObj = NULL; 265 } 266 267 env->DeleteGlobalRef(mCallbacksObj); 268} 269 270static jboolean connectHidNative(JNIEnv *env, jobject object, jbyteArray address) { 271 bt_status_t status; 272 jbyte *addr; 273 jboolean ret = JNI_TRUE; 274 if (!sBluetoothHidInterface) return JNI_FALSE; 275 276 addr = env->GetByteArrayElements(address, NULL); 277 if (!addr) { 278 ALOGE("Bluetooth device address null"); 279 return JNI_FALSE; 280 } 281 282 if ((status = sBluetoothHidInterface->connect((bt_bdaddr_t *) addr)) != 283 BT_STATUS_SUCCESS) { 284 ALOGE("Failed HID channel connection, status: %d", status); 285 ret = JNI_FALSE; 286 } 287 env->ReleaseByteArrayElements(address, addr, 0); 288 289 return ret; 290} 291 292static jboolean disconnectHidNative(JNIEnv *env, jobject object, jbyteArray address) { 293 bt_status_t status; 294 jbyte *addr; 295 jboolean ret = JNI_TRUE; 296 if (!sBluetoothHidInterface) return JNI_FALSE; 297 298 addr = env->GetByteArrayElements(address, NULL); 299 if (!addr) { 300 ALOGE("Bluetooth device address null"); 301 return JNI_FALSE; 302 } 303 304 if ( (status = sBluetoothHidInterface->disconnect((bt_bdaddr_t *) addr)) != 305 BT_STATUS_SUCCESS) { 306 ALOGE("Failed disconnect hid channel, status: %d", status); 307 ret = JNI_FALSE; 308 } 309 env->ReleaseByteArrayElements(address, addr, 0); 310 311 return ret; 312} 313 314static jboolean getProtocolModeNative(JNIEnv *env, jobject object, jbyteArray address) { 315 bt_status_t status; 316 jbyte *addr; 317 jboolean ret = JNI_TRUE; 318 bthh_protocol_mode_t protocolMode; 319 if (!sBluetoothHidInterface) return JNI_FALSE; 320 321 addr = env->GetByteArrayElements(address, NULL); 322 if (!addr) { 323 ALOGE("Bluetooth device address null"); 324 return JNI_FALSE; 325 } 326 327 if ( (status = sBluetoothHidInterface->get_protocol((bt_bdaddr_t *) addr, (bthh_protocol_mode_t) protocolMode)) != 328 BT_STATUS_SUCCESS) { 329 ALOGE("Failed get protocol mode, status: %d", status); 330 ret = JNI_FALSE; 331 } 332 env->ReleaseByteArrayElements(address, addr, 0); 333 334 return ret; 335} 336 337static jboolean virtualUnPlugNative(JNIEnv *env, jobject object, jbyteArray address) { 338 bt_status_t status; 339 jbyte *addr; 340 jboolean ret = JNI_TRUE; 341 if (!sBluetoothHidInterface) return JNI_FALSE; 342 343 addr = env->GetByteArrayElements(address, NULL); 344 if (!addr) { 345 ALOGE("Bluetooth device address null"); 346 return JNI_FALSE; 347 } 348 if ( (status = sBluetoothHidInterface->virtual_unplug((bt_bdaddr_t *) addr)) != 349 BT_STATUS_SUCCESS) { 350 ALOGE("Failed virual unplug, status: %d", status); 351 ret = JNI_FALSE; 352 } 353 env->ReleaseByteArrayElements(address, addr, 0); 354 return ret; 355 356} 357 358 359static jboolean setProtocolModeNative(JNIEnv *env, jobject object, jbyteArray address, jint protocolMode) { 360 bt_status_t status; 361 jbyte *addr; 362 jboolean ret = JNI_TRUE; 363 if (!sBluetoothHidInterface) return JNI_FALSE; 364 365 ALOGD("%s: protocolMode = %d", __FUNCTION__, protocolMode); 366 367 addr = env->GetByteArrayElements(address, NULL); 368 if (!addr) { 369 ALOGE("Bluetooth device address null"); 370 return JNI_FALSE; 371 } 372 373 bthh_protocol_mode_t mode; 374 switch(protocolMode){ 375 case 0: 376 mode = BTHH_REPORT_MODE; 377 break; 378 case 1: 379 mode = BTHH_BOOT_MODE; 380 break; 381 default: 382 ALOGE("Unknown HID protocol mode"); 383 return JNI_FALSE; 384 } 385 if ( (status = sBluetoothHidInterface->set_protocol((bt_bdaddr_t *) addr, mode)) != 386 BT_STATUS_SUCCESS) { 387 ALOGE("Failed set protocol mode, status: %d", status); 388 ret = JNI_FALSE; 389 } 390 env->ReleaseByteArrayElements(address, addr, 0); 391 392 return JNI_TRUE; 393} 394 395static jboolean getReportNative(JNIEnv *env, jobject object, jbyteArray address, jbyte reportType, jbyte reportId, jint bufferSize) { 396 ALOGV("%s: reportType = %d, reportId = %d, bufferSize = %d", __FUNCTION__, reportType, reportId, bufferSize); 397 398 bt_status_t status; 399 jbyte *addr; 400 jboolean ret = JNI_TRUE; 401 if (!sBluetoothHidInterface) return JNI_FALSE; 402 403 addr = env->GetByteArrayElements(address, NULL); 404 if (!addr) { 405 ALOGE("Bluetooth device address null"); 406 return JNI_FALSE; 407 } 408 409 jint rType = reportType; 410 jint rId = reportId; 411 412 if ( (status = sBluetoothHidInterface->get_report((bt_bdaddr_t *) addr, (bthh_report_type_t) rType, (uint8_t) rId, bufferSize)) != 413 BT_STATUS_SUCCESS) { 414 ALOGE("Failed get report, status: %d", status); 415 ret = JNI_FALSE; 416 } 417 env->ReleaseByteArrayElements(address, addr, 0); 418 419 return ret; 420} 421 422 423static jboolean setReportNative(JNIEnv *env, jobject object, jbyteArray address, jbyte reportType, jstring report) { 424 ALOGV("%s: reportType = %d", __FUNCTION__, reportType); 425 bt_status_t status; 426 jbyte *addr; 427 jboolean ret = JNI_TRUE; 428 if (!sBluetoothHidInterface) return JNI_FALSE; 429 430 addr = env->GetByteArrayElements(address, NULL); 431 if (!addr) { 432 ALOGE("Bluetooth device address null"); 433 return JNI_FALSE; 434 } 435 jint rType = reportType; 436 const char *c_report = env->GetStringUTFChars(report, NULL); 437 438 if ( (status = sBluetoothHidInterface->set_report((bt_bdaddr_t *) addr, (bthh_report_type_t)rType, (char*) c_report)) != 439 BT_STATUS_SUCCESS) { 440 ALOGE("Failed set report, status: %d", status); 441 ret = JNI_FALSE; 442 } 443 env->ReleaseStringUTFChars(report, c_report); 444 env->ReleaseByteArrayElements(address, addr, 0); 445 446 return ret; 447} 448 449static jboolean sendDataNative(JNIEnv *env, jobject object, jbyteArray address, jstring report) { 450 ALOGV("%s", __FUNCTION__); 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 const char *c_report = env->GetStringUTFChars(report, NULL); 462 if ( (status = sBluetoothHidInterface->send_data((bt_bdaddr_t *) addr, (char*) c_report)) != 463 BT_STATUS_SUCCESS) { 464 ALOGE("Failed set report, status: %d", status); 465 ret = JNI_FALSE; 466 } 467 env->ReleaseStringUTFChars(report, c_report); 468 env->ReleaseByteArrayElements(address, addr, 0); 469 470 return ret; 471 472} 473 474static JNINativeMethod sMethods[] = { 475 {"classInitNative", "()V", (void *) classInitNative}, 476 {"initializeNative", "()V", (void *) initializeNative}, 477 {"cleanupNative", "()V", (void *) cleanupNative}, 478 {"connectHidNative", "([B)Z", (void *) connectHidNative}, 479 {"disconnectHidNative", "([B)Z", (void *) disconnectHidNative}, 480 {"getProtocolModeNative", "([B)Z", (void *) getProtocolModeNative}, 481 {"virtualUnPlugNative", "([B)Z", (void *) virtualUnPlugNative}, 482 {"setProtocolModeNative", "([BB)Z", (void *) setProtocolModeNative}, 483 {"getReportNative", "([BBBI)Z", (void *) getReportNative}, 484 {"setReportNative", "([BBLjava/lang/String;)Z", (void *) setReportNative}, 485 {"sendDataNative", "([BLjava/lang/String;)Z", (void *) sendDataNative}, 486}; 487 488int register_com_android_bluetooth_hid(JNIEnv* env) 489{ 490 return jniRegisterNativeMethods(env, "com/android/bluetooth/hid/HidService", 491 sMethods, NELEM(sMethods)); 492} 493 494} 495