1 /* 2 * Copyright (c) 2014 The Android Open Source Project 3 * Copyright (C) 2012 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #define LOG_TAG "BluetoothHeadsetClientServiceJni" 19 #define LOG_NDEBUG 0 20 21 #include "android_runtime/AndroidRuntime.h" 22 #include "com_android_bluetooth.h" 23 #include "hardware/bt_hf_client.h" 24 #include "utils/Log.h" 25 26 namespace android { 27 28 static bthf_client_interface_t* sBluetoothHfpClientInterface = NULL; 29 static jobject mCallbacksObj = NULL; 30 31 static jmethodID method_onConnectionStateChanged; 32 static jmethodID method_onAudioStateChanged; 33 static jmethodID method_onVrStateChanged; 34 static jmethodID method_onNetworkState; 35 static jmethodID method_onNetworkRoaming; 36 static jmethodID method_onNetworkSignal; 37 static jmethodID method_onBatteryLevel; 38 static jmethodID method_onCurrentOperator; 39 static jmethodID method_onCall; 40 static jmethodID method_onCallSetup; 41 static jmethodID method_onCallHeld; 42 static jmethodID method_onRespAndHold; 43 static jmethodID method_onClip; 44 static jmethodID method_onCallWaiting; 45 static jmethodID method_onCurrentCalls; 46 static jmethodID method_onVolumeChange; 47 static jmethodID method_onCmdResult; 48 static jmethodID method_onSubscriberInfo; 49 static jmethodID method_onInBandRing; 50 static jmethodID method_onLastVoiceTagNumber; 51 static jmethodID method_onRingIndication; 52 53 static jbyteArray marshall_bda(const RawAddress* bd_addr) { 54 CallbackEnv sCallbackEnv(__func__); 55 if (!sCallbackEnv.valid()) return NULL; 56 57 jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(RawAddress)); 58 if (!addr) { 59 ALOGE("Fail to new jbyteArray bd addr"); 60 return NULL; 61 } 62 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(RawAddress), 63 (jbyte*)bd_addr); 64 return addr; 65 } 66 67 static void connection_state_cb(const RawAddress* bd_addr, 68 bthf_client_connection_state_t state, 69 unsigned int peer_feat, 70 unsigned int chld_feat) { 71 CallbackEnv sCallbackEnv(__func__); 72 if (!sCallbackEnv.valid()) return; 73 74 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr)); 75 if (!addr.get()) return; 76 77 ALOGD("%s: state %d peer_feat %d chld_feat %d", __func__, state, peer_feat, chld_feat); 78 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged, 79 (jint)state, (jint)peer_feat, (jint)chld_feat, 80 addr.get()); 81 } 82 83 static void audio_state_cb(const RawAddress* bd_addr, 84 bthf_client_audio_state_t state) { 85 CallbackEnv sCallbackEnv(__func__); 86 if (!sCallbackEnv.valid()) return; 87 88 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr)); 89 if (!addr.get()) return; 90 91 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioStateChanged, 92 (jint)state, addr.get()); 93 } 94 95 static void vr_cmd_cb(const RawAddress* bd_addr, bthf_client_vr_state_t state) { 96 CallbackEnv sCallbackEnv(__func__); 97 if (!sCallbackEnv.valid()) return; 98 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVrStateChanged, 99 (jint)state); 100 } 101 102 static void network_state_cb(const RawAddress* bd_addr, 103 bthf_client_network_state_t state) { 104 CallbackEnv sCallbackEnv(__func__); 105 if (!sCallbackEnv.valid()) return; 106 107 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr)); 108 if (!addr.get()) return; 109 110 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNetworkState, 111 (jint)state, addr.get()); 112 } 113 114 static void network_roaming_cb(const RawAddress* bd_addr, 115 bthf_client_service_type_t type) { 116 CallbackEnv sCallbackEnv(__func__); 117 118 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr)); 119 if (!addr.get()) return; 120 121 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNetworkRoaming, 122 (jint)type, addr.get()); 123 } 124 125 static void network_signal_cb(const RawAddress* bd_addr, int signal) { 126 CallbackEnv sCallbackEnv(__func__); 127 if (!sCallbackEnv.valid()) return; 128 129 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr)); 130 if (!addr.get()) return; 131 132 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNetworkSignal, 133 (jint)signal, addr.get()); 134 } 135 136 static void battery_level_cb(const RawAddress* bd_addr, int level) { 137 CallbackEnv sCallbackEnv(__func__); 138 if (!sCallbackEnv.valid()) return; 139 140 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr)); 141 if (!addr.get()) return; 142 143 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onBatteryLevel, 144 (jint)level, addr.get()); 145 } 146 147 static void current_operator_cb(const RawAddress* bd_addr, const char* name) { 148 CallbackEnv sCallbackEnv(__func__); 149 if (!sCallbackEnv.valid()) return; 150 151 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr)); 152 if (!addr.get()) return; 153 154 ScopedLocalRef<jstring> js_name(sCallbackEnv.get(), 155 sCallbackEnv->NewStringUTF(name)); 156 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCurrentOperator, 157 js_name.get(), addr.get()); 158 } 159 160 static void call_cb(const RawAddress* bd_addr, bthf_client_call_t call) { 161 CallbackEnv sCallbackEnv(__func__); 162 if (!sCallbackEnv.valid()) return; 163 164 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr)); 165 if (!addr.get()) return; 166 167 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCall, (jint)call, 168 addr.get()); 169 } 170 171 static void callsetup_cb(const RawAddress* bd_addr, 172 bthf_client_callsetup_t callsetup) { 173 CallbackEnv sCallbackEnv(__func__); 174 if (!sCallbackEnv.valid()) return; 175 176 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr)); 177 if (!addr.get()) return; 178 179 ALOGD("callsetup_cb bdaddr %02x:%02x:%02x:%02x:%02x:%02x", 180 bd_addr->address[0], bd_addr->address[1], bd_addr->address[2], 181 bd_addr->address[3], bd_addr->address[4], bd_addr->address[5]); 182 183 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCallSetup, 184 (jint)callsetup, addr.get()); 185 } 186 187 static void callheld_cb(const RawAddress* bd_addr, 188 bthf_client_callheld_t callheld) { 189 CallbackEnv sCallbackEnv(__func__); 190 if (!sCallbackEnv.valid()) return; 191 192 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr)); 193 if (!addr.get()) return; 194 195 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCallHeld, (jint)callheld, 196 addr.get()); 197 } 198 199 static void resp_and_hold_cb(const RawAddress* bd_addr, 200 bthf_client_resp_and_hold_t resp_and_hold) { 201 CallbackEnv sCallbackEnv(__func__); 202 if (!sCallbackEnv.valid()) return; 203 204 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr)); 205 if (!addr.get()) return; 206 207 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onRespAndHold, 208 (jint)resp_and_hold, addr.get()); 209 } 210 211 static void clip_cb(const RawAddress* bd_addr, const char* number) { 212 CallbackEnv sCallbackEnv(__func__); 213 if (!sCallbackEnv.valid()) return; 214 215 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr)); 216 if (!addr.get()) return; 217 218 ScopedLocalRef<jstring> js_number(sCallbackEnv.get(), 219 sCallbackEnv->NewStringUTF(number)); 220 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onClip, js_number.get(), 221 addr.get()); 222 } 223 224 static void call_waiting_cb(const RawAddress* bd_addr, const char* number) { 225 CallbackEnv sCallbackEnv(__func__); 226 if (!sCallbackEnv.valid()) return; 227 228 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr)); 229 if (!addr.get()) return; 230 ScopedLocalRef<jstring> js_number(sCallbackEnv.get(), 231 sCallbackEnv->NewStringUTF(number)); 232 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCallWaiting, 233 js_number.get(), addr.get()); 234 } 235 236 static void current_calls_cb(const RawAddress* bd_addr, int index, 237 bthf_client_call_direction_t dir, 238 bthf_client_call_state_t state, 239 bthf_client_call_mpty_type_t mpty, 240 const char* number) { 241 CallbackEnv sCallbackEnv(__func__); 242 if (!sCallbackEnv.valid()) return; 243 244 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr)); 245 if (!addr.get()) return; 246 ScopedLocalRef<jstring> js_number(sCallbackEnv.get(), 247 sCallbackEnv->NewStringUTF(number)); 248 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCurrentCalls, index, dir, 249 state, mpty, js_number.get(), addr.get()); 250 } 251 252 static void volume_change_cb(const RawAddress* bd_addr, 253 bthf_client_volume_type_t type, int volume) { 254 CallbackEnv sCallbackEnv(__func__); 255 if (!sCallbackEnv.valid()) return; 256 257 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr)); 258 if (!addr.get()) return; 259 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVolumeChange, (jint)type, 260 (jint)volume, addr.get()); 261 } 262 263 static void cmd_complete_cb(const RawAddress* bd_addr, 264 bthf_client_cmd_complete_t type, int cme) { 265 CallbackEnv sCallbackEnv(__func__); 266 if (!sCallbackEnv.valid()) return; 267 268 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr)); 269 if (!addr.get()) return; 270 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCmdResult, (jint)type, 271 (jint)cme, addr.get()); 272 } 273 274 static void subscriber_info_cb(const RawAddress* bd_addr, const char* name, 275 bthf_client_subscriber_service_type_t type) { 276 CallbackEnv sCallbackEnv(__func__); 277 if (!sCallbackEnv.valid()) return; 278 279 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr)); 280 if (!addr.get()) return; 281 ScopedLocalRef<jstring> js_name(sCallbackEnv.get(), 282 sCallbackEnv->NewStringUTF(name)); 283 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onSubscriberInfo, 284 js_name.get(), (jint)type, addr.get()); 285 } 286 287 static void in_band_ring_cb(const RawAddress* bd_addr, 288 bthf_client_in_band_ring_state_t in_band) { 289 CallbackEnv sCallbackEnv(__func__); 290 if (!sCallbackEnv.valid()) return; 291 292 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr)); 293 if (!addr.get()) return; 294 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onInBandRing, 295 (jint)in_band, addr.get()); 296 } 297 298 static void last_voice_tag_number_cb(const RawAddress* bd_addr, 299 const char* number) { 300 CallbackEnv sCallbackEnv(__func__); 301 if (!sCallbackEnv.valid()) return; 302 303 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr)); 304 if (!addr.get()) return; 305 ScopedLocalRef<jstring> js_number(sCallbackEnv.get(), 306 sCallbackEnv->NewStringUTF(number)); 307 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onLastVoiceTagNumber, 308 js_number.get(), addr.get()); 309 } 310 311 static void ring_indication_cb(const RawAddress* bd_addr) { 312 CallbackEnv sCallbackEnv(__func__); 313 if (!sCallbackEnv.valid()) return; 314 315 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr)); 316 if (!addr.get()) return; 317 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onRingIndication, 318 addr.get()); 319 } 320 321 static bthf_client_callbacks_t sBluetoothHfpClientCallbacks = { 322 sizeof(sBluetoothHfpClientCallbacks), 323 connection_state_cb, 324 audio_state_cb, 325 vr_cmd_cb, 326 network_state_cb, 327 network_roaming_cb, 328 network_signal_cb, 329 battery_level_cb, 330 current_operator_cb, 331 call_cb, 332 callsetup_cb, 333 callheld_cb, 334 resp_and_hold_cb, 335 clip_cb, 336 call_waiting_cb, 337 current_calls_cb, 338 volume_change_cb, 339 cmd_complete_cb, 340 subscriber_info_cb, 341 in_band_ring_cb, 342 last_voice_tag_number_cb, 343 ring_indication_cb, 344 }; 345 346 static void classInitNative(JNIEnv* env, jclass clazz) { 347 method_onConnectionStateChanged = 348 env->GetMethodID(clazz, "onConnectionStateChanged", "(III[B)V"); 349 method_onAudioStateChanged = 350 env->GetMethodID(clazz, "onAudioStateChanged", "(I[B)V"); 351 method_onVrStateChanged = env->GetMethodID(clazz, "onVrStateChanged", "(I)V"); 352 method_onNetworkState = env->GetMethodID(clazz, "onNetworkState", "(I[B)V"); 353 method_onNetworkRoaming = env->GetMethodID(clazz, "onNetworkRoaming", "(I[B)V"); 354 method_onNetworkSignal = env->GetMethodID(clazz, "onNetworkSignal", "(I[B)V"); 355 method_onBatteryLevel = env->GetMethodID(clazz, "onBatteryLevel", "(I[B)V"); 356 method_onCurrentOperator = 357 env->GetMethodID(clazz, "onCurrentOperator", "(Ljava/lang/String;[B)V"); 358 method_onCall = env->GetMethodID(clazz, "onCall", "(I[B)V"); 359 method_onCallSetup = env->GetMethodID(clazz, "onCallSetup", "(I[B)V"); 360 method_onCallHeld = env->GetMethodID(clazz, "onCallHeld", "(I[B)V"); 361 method_onRespAndHold = env->GetMethodID(clazz, "onRespAndHold", "(I[B)V"); 362 method_onClip = env->GetMethodID(clazz, "onClip", "(Ljava/lang/String;[B)V"); 363 method_onCallWaiting = 364 env->GetMethodID(clazz, "onCallWaiting", "(Ljava/lang/String;[B)V"); 365 method_onCurrentCalls = 366 env->GetMethodID(clazz, "onCurrentCalls", "(IIIILjava/lang/String;[B)V"); 367 method_onVolumeChange = env->GetMethodID(clazz, "onVolumeChange", "(II[B)V"); 368 method_onCmdResult = env->GetMethodID(clazz, "onCmdResult", "(II[B)V"); 369 method_onSubscriberInfo = 370 env->GetMethodID(clazz, "onSubscriberInfo", "(Ljava/lang/String;I[B)V"); 371 method_onInBandRing = env->GetMethodID(clazz, "onInBandRing", "(I[B)V"); 372 method_onLastVoiceTagNumber = 373 env->GetMethodID(clazz, "onLastVoiceTagNumber", "(Ljava/lang/String;[B)V"); 374 method_onRingIndication = env->GetMethodID(clazz, "onRingIndication", "([B)V"); 375 376 ALOGI("%s succeeds", __func__); 377 } 378 379 static void initializeNative(JNIEnv* env, jobject object) { 380 ALOGD("%s: HfpClient", __func__); 381 const bt_interface_t* btInf = getBluetoothInterface(); 382 if (btInf == NULL) { 383 ALOGE("Bluetooth module is not loaded"); 384 return; 385 } 386 387 if (sBluetoothHfpClientInterface != NULL) { 388 ALOGW("Cleaning up Bluetooth HFP Client Interface before initializing"); 389 sBluetoothHfpClientInterface->cleanup(); 390 sBluetoothHfpClientInterface = NULL; 391 } 392 393 if (mCallbacksObj != NULL) { 394 ALOGW("Cleaning up Bluetooth HFP Client callback object"); 395 env->DeleteGlobalRef(mCallbacksObj); 396 mCallbacksObj = NULL; 397 } 398 399 sBluetoothHfpClientInterface = 400 (bthf_client_interface_t*)btInf->get_profile_interface( 401 BT_PROFILE_HANDSFREE_CLIENT_ID); 402 if (sBluetoothHfpClientInterface == NULL) { 403 ALOGE("Failed to get Bluetooth HFP Client Interface"); 404 return; 405 } 406 407 bt_status_t status = 408 sBluetoothHfpClientInterface->init(&sBluetoothHfpClientCallbacks); 409 if (status != BT_STATUS_SUCCESS) { 410 ALOGE("Failed to initialize Bluetooth HFP Client, status: %d", status); 411 sBluetoothHfpClientInterface = NULL; 412 return; 413 } 414 415 mCallbacksObj = env->NewGlobalRef(object); 416 } 417 418 static void cleanupNative(JNIEnv* env, jobject object) { 419 const bt_interface_t* btInf = getBluetoothInterface(); 420 if (btInf == NULL) { 421 ALOGE("Bluetooth module is not loaded"); 422 return; 423 } 424 425 if (sBluetoothHfpClientInterface != NULL) { 426 ALOGW("Cleaning up Bluetooth HFP Client Interface..."); 427 sBluetoothHfpClientInterface->cleanup(); 428 sBluetoothHfpClientInterface = NULL; 429 } 430 431 if (mCallbacksObj != NULL) { 432 ALOGW("Cleaning up Bluetooth HFP Client callback object"); 433 env->DeleteGlobalRef(mCallbacksObj); 434 mCallbacksObj = NULL; 435 } 436 } 437 438 static jboolean connectNative(JNIEnv* env, jobject object, jbyteArray address) { 439 if (!sBluetoothHfpClientInterface) return JNI_FALSE; 440 441 jbyte* addr = env->GetByteArrayElements(address, NULL); 442 if (!addr) { 443 jniThrowIOException(env, EINVAL); 444 return JNI_FALSE; 445 } 446 447 bt_status_t status = sBluetoothHfpClientInterface->connect((RawAddress*)addr); 448 if (status != BT_STATUS_SUCCESS) { 449 ALOGE("Failed AG connection, status: %d", status); 450 } 451 env->ReleaseByteArrayElements(address, addr, 0); 452 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 453 } 454 455 static jboolean disconnectNative(JNIEnv* env, jobject object, 456 jbyteArray address) { 457 if (!sBluetoothHfpClientInterface) return JNI_FALSE; 458 459 jbyte* addr = env->GetByteArrayElements(address, NULL); 460 if (!addr) { 461 jniThrowIOException(env, EINVAL); 462 return JNI_FALSE; 463 } 464 465 bt_status_t status = 466 sBluetoothHfpClientInterface->disconnect((const RawAddress*)addr); 467 if (status != BT_STATUS_SUCCESS) { 468 ALOGE("Failed AG disconnection, status: %d", status); 469 } 470 env->ReleaseByteArrayElements(address, addr, 0); 471 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 472 } 473 474 static jboolean connectAudioNative(JNIEnv* env, jobject object, 475 jbyteArray address) { 476 if (!sBluetoothHfpClientInterface) return JNI_FALSE; 477 478 jbyte* addr = env->GetByteArrayElements(address, NULL); 479 if (!addr) { 480 jniThrowIOException(env, EINVAL); 481 return JNI_FALSE; 482 } 483 484 bt_status_t status = 485 sBluetoothHfpClientInterface->connect_audio((const RawAddress*)addr); 486 if (status != BT_STATUS_SUCCESS) { 487 ALOGE("Failed AG audio connection, status: %d", status); 488 } 489 env->ReleaseByteArrayElements(address, addr, 0); 490 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 491 } 492 493 static jboolean disconnectAudioNative(JNIEnv* env, jobject object, 494 jbyteArray address) { 495 if (!sBluetoothHfpClientInterface) return JNI_FALSE; 496 497 jbyte* addr = env->GetByteArrayElements(address, NULL); 498 if (!addr) { 499 jniThrowIOException(env, EINVAL); 500 return JNI_FALSE; 501 } 502 503 bt_status_t status = 504 sBluetoothHfpClientInterface->disconnect_audio((const RawAddress*)addr); 505 if (status != BT_STATUS_SUCCESS) { 506 ALOGE("Failed AG audio disconnection, status: %d", status); 507 } 508 env->ReleaseByteArrayElements(address, addr, 0); 509 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 510 } 511 512 static jboolean startVoiceRecognitionNative(JNIEnv* env, jobject object, 513 jbyteArray address) { 514 if (!sBluetoothHfpClientInterface) return JNI_FALSE; 515 516 jbyte* addr = env->GetByteArrayElements(address, NULL); 517 if (!addr) { 518 jniThrowIOException(env, EINVAL); 519 return JNI_FALSE; 520 } 521 522 bt_status_t status = sBluetoothHfpClientInterface->start_voice_recognition( 523 (const RawAddress*)addr); 524 if (status != BT_STATUS_SUCCESS) { 525 ALOGE("Failed to start voice recognition, status: %d", status); 526 } 527 env->ReleaseByteArrayElements(address, addr, 0); 528 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 529 } 530 531 static jboolean stopVoiceRecognitionNative(JNIEnv* env, jobject object, 532 jbyteArray address) { 533 if (!sBluetoothHfpClientInterface) return JNI_FALSE; 534 535 jbyte* addr = env->GetByteArrayElements(address, NULL); 536 if (!addr) { 537 jniThrowIOException(env, EINVAL); 538 return JNI_FALSE; 539 } 540 541 bt_status_t status = sBluetoothHfpClientInterface->stop_voice_recognition( 542 (const RawAddress*)addr); 543 if (status != BT_STATUS_SUCCESS) { 544 ALOGE("Failed to stop voice recognition, status: %d", status); 545 } 546 env->ReleaseByteArrayElements(address, addr, 0); 547 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 548 } 549 550 static jboolean setVolumeNative(JNIEnv* env, jobject object, jbyteArray address, 551 jint volume_type, jint volume) { 552 if (!sBluetoothHfpClientInterface) return JNI_FALSE; 553 554 jbyte* addr = env->GetByteArrayElements(address, NULL); 555 if (!addr) { 556 jniThrowIOException(env, EINVAL); 557 return JNI_FALSE; 558 } 559 560 bt_status_t status = sBluetoothHfpClientInterface->volume_control( 561 (const RawAddress*)addr, (bthf_client_volume_type_t)volume_type, volume); 562 if (status != BT_STATUS_SUCCESS) { 563 ALOGE("FAILED to control volume, status: %d", status); 564 } 565 env->ReleaseByteArrayElements(address, addr, 0); 566 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 567 } 568 569 static jboolean dialNative(JNIEnv* env, jobject object, jbyteArray address, 570 jstring number_str) { 571 if (!sBluetoothHfpClientInterface) return JNI_FALSE; 572 573 jbyte* addr = env->GetByteArrayElements(address, NULL); 574 if (!addr) { 575 jniThrowIOException(env, EINVAL); 576 return JNI_FALSE; 577 } 578 579 const char* number = NULL; 580 if (number_str != NULL) { 581 number = env->GetStringUTFChars(number_str, NULL); 582 } 583 584 bt_status_t status = 585 sBluetoothHfpClientInterface->dial((const RawAddress*)addr, number); 586 if (status != BT_STATUS_SUCCESS) { 587 ALOGE("Failed to dial, status: %d", status); 588 } 589 if (number != NULL) { 590 env->ReleaseStringUTFChars(number_str, number); 591 } 592 env->ReleaseByteArrayElements(address, addr, 0); 593 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 594 } 595 596 static jboolean dialMemoryNative(JNIEnv* env, jobject object, 597 jbyteArray address, jint location) { 598 if (!sBluetoothHfpClientInterface) return JNI_FALSE; 599 600 jbyte* addr = env->GetByteArrayElements(address, NULL); 601 if (!addr) { 602 jniThrowIOException(env, EINVAL); 603 return JNI_FALSE; 604 } 605 606 bt_status_t status = sBluetoothHfpClientInterface->dial_memory( 607 (const RawAddress*)addr, (int)location); 608 if (status != BT_STATUS_SUCCESS) { 609 ALOGE("Failed to dial from memory, status: %d", status); 610 } 611 612 env->ReleaseByteArrayElements(address, addr, 0); 613 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 614 } 615 616 static jboolean handleCallActionNative(JNIEnv* env, jobject object, 617 jbyteArray address, jint action, 618 jint index) { 619 if (!sBluetoothHfpClientInterface) return JNI_FALSE; 620 621 jbyte* addr = env->GetByteArrayElements(address, NULL); 622 if (!addr) { 623 jniThrowIOException(env, EINVAL); 624 return JNI_FALSE; 625 } 626 627 bt_status_t status = sBluetoothHfpClientInterface->handle_call_action( 628 (const RawAddress*)addr, (bthf_client_call_action_t)action, (int)index); 629 630 if (status != BT_STATUS_SUCCESS) { 631 ALOGE("Failed to enter private mode, status: %d", status); 632 } 633 env->ReleaseByteArrayElements(address, addr, 0); 634 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 635 } 636 637 static jboolean queryCurrentCallsNative(JNIEnv* env, jobject object, 638 jbyteArray address) { 639 if (!sBluetoothHfpClientInterface) return JNI_FALSE; 640 641 jbyte* addr = env->GetByteArrayElements(address, NULL); 642 if (!addr) { 643 jniThrowIOException(env, EINVAL); 644 return JNI_FALSE; 645 } 646 647 bt_status_t status = sBluetoothHfpClientInterface->query_current_calls( 648 (const RawAddress*)addr); 649 650 if (status != BT_STATUS_SUCCESS) { 651 ALOGE("Failed to query current calls, status: %d", status); 652 } 653 env->ReleaseByteArrayElements(address, addr, 0); 654 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 655 } 656 657 static jboolean queryCurrentOperatorNameNative(JNIEnv* env, jobject object, 658 jbyteArray address) { 659 if (!sBluetoothHfpClientInterface) return JNI_FALSE; 660 661 jbyte* addr = env->GetByteArrayElements(address, NULL); 662 if (!addr) { 663 jniThrowIOException(env, EINVAL); 664 return JNI_FALSE; 665 } 666 667 bt_status_t status = 668 sBluetoothHfpClientInterface->query_current_operator_name( 669 (const RawAddress*)addr); 670 if (status != BT_STATUS_SUCCESS) { 671 ALOGE("Failed to query current operator name, status: %d", status); 672 } 673 674 env->ReleaseByteArrayElements(address, addr, 0); 675 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 676 } 677 678 static jboolean retrieveSubscriberInfoNative(JNIEnv* env, jobject object, 679 jbyteArray address) { 680 if (!sBluetoothHfpClientInterface) return JNI_FALSE; 681 682 jbyte* addr = env->GetByteArrayElements(address, NULL); 683 if (!addr) { 684 jniThrowIOException(env, EINVAL); 685 return JNI_FALSE; 686 } 687 688 bt_status_t status = sBluetoothHfpClientInterface->retrieve_subscriber_info( 689 (const RawAddress*)addr); 690 if (status != BT_STATUS_SUCCESS) { 691 ALOGE("Failed to retrieve subscriber info, status: %d", status); 692 } 693 694 env->ReleaseByteArrayElements(address, addr, 0); 695 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 696 } 697 698 static jboolean sendDtmfNative(JNIEnv* env, jobject object, jbyteArray address, 699 jbyte code) { 700 if (!sBluetoothHfpClientInterface) return JNI_FALSE; 701 702 jbyte* addr = env->GetByteArrayElements(address, NULL); 703 if (!addr) { 704 jniThrowIOException(env, EINVAL); 705 return JNI_FALSE; 706 } 707 708 bt_status_t status = sBluetoothHfpClientInterface->send_dtmf( 709 (const RawAddress*)addr, (char)code); 710 if (status != BT_STATUS_SUCCESS) { 711 ALOGE("Failed to send DTMF, status: %d", status); 712 } 713 714 env->ReleaseByteArrayElements(address, addr, 0); 715 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 716 } 717 718 static jboolean requestLastVoiceTagNumberNative(JNIEnv* env, jobject object, 719 jbyteArray address) { 720 if (!sBluetoothHfpClientInterface) return JNI_FALSE; 721 722 jbyte* addr = env->GetByteArrayElements(address, NULL); 723 if (!addr) { 724 jniThrowIOException(env, EINVAL); 725 return JNI_FALSE; 726 } 727 728 bt_status_t status = 729 sBluetoothHfpClientInterface->request_last_voice_tag_number( 730 (const RawAddress*)addr); 731 732 if (status != BT_STATUS_SUCCESS) { 733 ALOGE("Failed to request last Voice Tag number, status: %d", status); 734 } 735 736 env->ReleaseByteArrayElements(address, addr, 0); 737 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 738 } 739 740 static jboolean sendATCmdNative(JNIEnv* env, jobject object, jbyteArray address, 741 jint cmd, jint val1, jint val2, 742 jstring arg_str) { 743 if (!sBluetoothHfpClientInterface) return JNI_FALSE; 744 745 jbyte* addr = env->GetByteArrayElements(address, NULL); 746 if (!addr) { 747 jniThrowIOException(env, EINVAL); 748 return JNI_FALSE; 749 } 750 751 const char* arg = NULL; 752 if (arg_str != NULL) { 753 arg = env->GetStringUTFChars(arg_str, NULL); 754 } 755 756 bt_status_t status = sBluetoothHfpClientInterface->send_at_cmd( 757 (const RawAddress*)addr, cmd, val1, val2, arg); 758 759 if (status != BT_STATUS_SUCCESS) { 760 ALOGE("Failed to send cmd, status: %d", status); 761 } 762 763 if (arg != NULL) { 764 env->ReleaseStringUTFChars(arg_str, arg); 765 } 766 767 env->ReleaseByteArrayElements(address, addr, 0); 768 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 769 } 770 771 static JNINativeMethod sMethods[] = { 772 {"classInitNative", "()V", (void*)classInitNative}, 773 {"initializeNative", "()V", (void*)initializeNative}, 774 {"cleanupNative", "()V", (void*)cleanupNative}, 775 {"connectNative", "([B)Z", (void*)connectNative}, 776 {"disconnectNative", "([B)Z", (void*)disconnectNative}, 777 {"connectAudioNative", "([B)Z", (void*)connectAudioNative}, 778 {"disconnectAudioNative", "([B)Z", (void*)disconnectAudioNative}, 779 {"startVoiceRecognitionNative", "([B)Z", 780 (void*)startVoiceRecognitionNative}, 781 {"stopVoiceRecognitionNative", "([B)Z", (void*)stopVoiceRecognitionNative}, 782 {"setVolumeNative", "([BII)Z", (void*)setVolumeNative}, 783 {"dialNative", "([BLjava/lang/String;)Z", (void*)dialNative}, 784 {"dialMemoryNative", "([BI)Z", (void*)dialMemoryNative}, 785 {"handleCallActionNative", "([BII)Z", (void*)handleCallActionNative}, 786 {"queryCurrentCallsNative", "([B)Z", (void*)queryCurrentCallsNative}, 787 {"queryCurrentOperatorNameNative", "([B)Z", 788 (void*)queryCurrentOperatorNameNative}, 789 {"retrieveSubscriberInfoNative", "([B)Z", 790 (void*)retrieveSubscriberInfoNative}, 791 {"sendDtmfNative", "([BB)Z", (void*)sendDtmfNative}, 792 {"requestLastVoiceTagNumberNative", "([B)Z", 793 (void*)requestLastVoiceTagNumberNative}, 794 {"sendATCmdNative", "([BIIILjava/lang/String;)Z", (void*)sendATCmdNative}, 795 }; 796 797 int register_com_android_bluetooth_hfpclient(JNIEnv* env) { 798 return jniRegisterNativeMethods( 799 env, "com/android/bluetooth/hfpclient/NativeInterface", 800 sMethods, NELEM(sMethods)); 801 } 802 803 } /* namespace android */ 804