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 "BluetoothAvrcpControllerJni" 18 19#define LOG_NDEBUG 0 20 21#include "com_android_bluetooth.h" 22#include "hardware/bt_rc.h" 23#include "utils/Log.h" 24#include "android_runtime/AndroidRuntime.h" 25 26#include <string.h> 27 28namespace android { 29static jmethodID method_handlePassthroughRsp; 30static jmethodID method_onConnectionStateChanged; 31static jmethodID method_getRcFeatures; 32static jmethodID method_setplayerappsettingrsp; 33static jmethodID method_handleplayerappsetting; 34static jmethodID method_handleplayerappsettingchanged; 35static jmethodID method_handleSetAbsVolume; 36static jmethodID method_handleRegisterNotificationAbsVol; 37static jmethodID method_handletrackchanged; 38static jmethodID method_handleplaypositionchanged; 39static jmethodID method_handleplaystatuschanged; 40static jmethodID method_handleGroupNavigationRsp; 41 42 43static const btrc_ctrl_interface_t *sBluetoothAvrcpInterface = NULL; 44static jobject mCallbacksObj = NULL; 45static JNIEnv *sCallbackEnv = NULL; 46 47static bool checkCallbackThread() { 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 sCallbackEnv = getCallbackEnv(); 53 54 JNIEnv* env = AndroidRuntime::getJNIEnv(); 55 if (sCallbackEnv != env || sCallbackEnv == NULL) return false; 56 return true; 57} 58 59static void btavrcp_passthrough_response_callback(int id, int pressed) { 60 ALOGI("%s", __FUNCTION__); 61 ALOGI("id: %d, pressed: %d", id, pressed); 62 63 if (!checkCallbackThread()) { 64 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); 65 return; 66 } 67 68 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handlePassthroughRsp, (jint)id, 69 (jint)pressed); 70 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 71} 72 73static void btavrcp_groupnavigation_response_callback(int id, int pressed) { 74 ALOGI("%s", __FUNCTION__); 75 76 if (!checkCallbackThread()) { 77 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); 78 return; 79 } 80 81 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handleGroupNavigationRsp, (jint)id, 82 (jint)pressed); 83 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 84} 85 86static void btavrcp_connection_state_callback(bool state, bt_bdaddr_t* bd_addr) { 87 jbyteArray addr; 88 89 ALOGI("%s", __FUNCTION__); 90 ALOGI("conn state: %d", state); 91 92 if (!checkCallbackThread()) { \ 93 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \ 94 return; \ 95 } 96 97 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 98 if (!addr) { 99 ALOGE("Fail to new jbyteArray bd addr for connection state"); 100 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 101 return; 102 } 103 104 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr); 105 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged, (jboolean) state, 106 addr); 107 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 108 sCallbackEnv->DeleteLocalRef(addr); 109} 110 111static void btavrcp_get_rcfeatures_callback(bt_bdaddr_t *bd_addr, int features) { 112 jbyteArray addr; 113 114 ALOGI("%s", __FUNCTION__); 115 116 if (!checkCallbackThread()) { \ 117 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \ 118 return; \ 119 } 120 121 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 122 if (!addr) { 123 ALOGE("Fail to new jbyteArray bd addr "); 124 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 125 return; 126 } 127 128 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr); 129 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getRcFeatures, addr, (jint)features); 130 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 131 sCallbackEnv->DeleteLocalRef(addr); 132} 133 134static void btavrcp_setplayerapplicationsetting_rsp_callback(bt_bdaddr_t *bd_addr, 135 uint8_t accepted) { 136 jbyteArray addr; 137 138 ALOGI("%s", __FUNCTION__); 139 140 if (!checkCallbackThread()) { \ 141 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \ 142 return; \ 143 } 144 145 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 146 if (!addr) { 147 ALOGE("Fail to new jbyteArray bd addr "); 148 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 149 return; 150 } 151 152 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr); 153 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_setplayerappsettingrsp, addr, (jint)accepted); 154 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 155 sCallbackEnv->DeleteLocalRef(addr); 156} 157 158static void btavrcp_playerapplicationsetting_callback(bt_bdaddr_t *bd_addr, uint8_t num_attr, 159 btrc_player_app_attr_t *app_attrs, uint8_t num_ext_attr, 160 btrc_player_app_ext_attr_t *ext_attrs) { 161 ALOGI("%s", __FUNCTION__); 162 jbyteArray addr; 163 jbyteArray playerattribs; 164 jint arraylen; 165 int i,k; 166 167 if (!checkCallbackThread()) { \ 168 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \ 169 return; \ 170 } 171 172 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 173 if (!addr) { 174 ALOGE("Fail to new jbyteArray bd addr "); 175 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 176 return; 177 } 178 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*)bd_addr); 179 /* TODO ext attrs 180 * Flattening defined attributes: <id,num_values,values[]> 181 */ 182 arraylen = 0; 183 for (i = 0; i < num_attr; i++) 184 { 185 /*2 bytes for id and num */ 186 arraylen += 2 + app_attrs[i].num_val; 187 } 188 ALOGI(" arraylen %d", arraylen); 189 playerattribs = sCallbackEnv->NewByteArray(arraylen); 190 if(!playerattribs) 191 { 192 ALOGE("Fail to new jbyteArray playerattribs "); 193 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 194 sCallbackEnv->DeleteLocalRef(addr); 195 return; 196 } 197 k= 0; 198 for (i = 0; (i < num_attr)&&(k < arraylen); i++) 199 { 200 sCallbackEnv->SetByteArrayRegion(playerattribs, k, 1, (jbyte*)&(app_attrs[i].attr_id)); 201 k++; 202 sCallbackEnv->SetByteArrayRegion(playerattribs, k, 1, (jbyte*)&(app_attrs[i].num_val)); 203 k++; 204 sCallbackEnv->SetByteArrayRegion(playerattribs, k, app_attrs[i].num_val, 205 (jbyte*)(app_attrs[i].attr_val)); 206 k = k + app_attrs[i].num_val; 207 } 208 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handleplayerappsetting, addr, 209 playerattribs, (jint)arraylen); 210 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 211 sCallbackEnv->DeleteLocalRef(addr); 212 sCallbackEnv->DeleteLocalRef(playerattribs); 213} 214 215static void btavrcp_playerapplicationsetting_changed_callback(bt_bdaddr_t *bd_addr, 216 btrc_player_settings_t *p_vals) { 217 218 jbyteArray addr; 219 jbyteArray playerattribs; 220 int i, k, arraylen; 221 ALOGI("%s", __FUNCTION__); 222 223 if (!checkCallbackThread()) { \ 224 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \ 225 return; \ 226 } 227 228 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 229 if ((!addr)) { 230 ALOGE("Fail to get new array "); 231 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 232 return; 233 } 234 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*)bd_addr); 235 arraylen = p_vals->num_attr*2; 236 playerattribs = sCallbackEnv->NewByteArray(arraylen); 237 if(!playerattribs) 238 { 239 ALOGE("Fail to new jbyteArray playerattribs "); 240 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 241 sCallbackEnv->DeleteLocalRef(addr); 242 return; 243 } 244 /* 245 * Flatening format: <id,val> 246 */ 247 k = 0; 248 for (i = 0; (i < p_vals->num_attr)&&( k < arraylen);i++) 249 { 250 sCallbackEnv->SetByteArrayRegion(playerattribs, k, 1, (jbyte*)&(p_vals->attr_ids[i])); 251 k++; 252 sCallbackEnv->SetByteArrayRegion(playerattribs, k, 1, (jbyte*)&(p_vals->attr_values[i])); 253 k++; 254 } 255 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handleplayerappsettingchanged, addr, 256 playerattribs, (jint)arraylen); 257 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 258 sCallbackEnv->DeleteLocalRef(addr); 259 sCallbackEnv->DeleteLocalRef(playerattribs); 260} 261 262static void btavrcp_set_abs_vol_cmd_callback(bt_bdaddr_t *bd_addr, uint8_t abs_vol, 263 uint8_t label) { 264 265 jbyteArray addr; 266 ALOGI("%s", __FUNCTION__); 267 268 if (!checkCallbackThread()) { \ 269 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \ 270 return; \ 271 } 272 273 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 274 if ((!addr)) { 275 ALOGE("Fail to get new array "); 276 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 277 return; 278 } 279 280 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*)bd_addr); 281 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handleSetAbsVolume, addr, (jbyte)abs_vol, 282 (jbyte)label); 283 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 284 sCallbackEnv->DeleteLocalRef(addr); 285} 286 287static void btavrcp_register_notification_absvol_callback(bt_bdaddr_t *bd_addr, uint8_t label) { 288 jbyteArray addr; 289 290 ALOGI("%s", __FUNCTION__); 291 292 if (!checkCallbackThread()) { \ 293 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \ 294 return; \ 295 } 296 297 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 298 if ((!addr)) { 299 ALOGE("Fail to get new array "); 300 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 301 return; 302 } 303 304 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*)bd_addr); 305 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handleRegisterNotificationAbsVol, addr, 306 (jbyte)label); 307 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 308 sCallbackEnv->DeleteLocalRef(addr); 309} 310 311static void btavrcp_track_changed_callback(bt_bdaddr_t *bd_addr, uint8_t num_attr, 312 btrc_element_attr_val_t *p_attrs) { 313 /* 314 * byteArray will be formatted like this: id,len,string 315 * Assuming text feild to be null terminated. 316 */ 317 jbyteArray addr; 318 jintArray attribIds; 319 jobjectArray stringArray; 320 jstring str; 321 jclass strclazz; 322 jint i; 323 ALOGI("%s", __FUNCTION__); 324 if (!checkCallbackThread()) { \ 325 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \ 326 return; \ 327 } 328 329 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 330 if ((!addr)) { 331 ALOGE("Fail to get new array "); 332 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 333 return; 334 } 335 attribIds = sCallbackEnv->NewIntArray(num_attr); 336 if(!attribIds) { 337 ALOGE(" failed to set new array for attribIds"); 338 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 339 sCallbackEnv->DeleteLocalRef(addr); 340 return; 341 } 342 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*)bd_addr); 343 344 strclazz = sCallbackEnv->FindClass("java/lang/String"); 345 stringArray = sCallbackEnv->NewObjectArray((jint)num_attr, strclazz, 0); 346 if(!stringArray) { 347 ALOGE(" failed to get String array"); 348 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 349 sCallbackEnv->DeleteLocalRef(addr); 350 sCallbackEnv->DeleteLocalRef(attribIds); 351 return; 352 } 353 for(i = 0; i < num_attr; i++) 354 { 355 str = sCallbackEnv->NewStringUTF((char*)(p_attrs[i].text)); 356 if(!str) { 357 ALOGE(" Unable to get str "); 358 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 359 sCallbackEnv->DeleteLocalRef(addr); 360 sCallbackEnv->DeleteLocalRef(attribIds); 361 sCallbackEnv->DeleteLocalRef(stringArray); 362 return; 363 } 364 sCallbackEnv->SetIntArrayRegion(attribIds, i, 1, (jint*)&(p_attrs[i].attr_id)); 365 sCallbackEnv->SetObjectArrayElement(stringArray, i,str); 366 sCallbackEnv->DeleteLocalRef(str); 367 } 368 369 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handletrackchanged, addr, 370 (jbyte)(num_attr), attribIds, stringArray); 371 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 372 sCallbackEnv->DeleteLocalRef(addr); 373 sCallbackEnv->DeleteLocalRef(attribIds); 374 /* TODO check do we need to delete str seperately or not */ 375 sCallbackEnv->DeleteLocalRef(stringArray); 376 sCallbackEnv->DeleteLocalRef(strclazz); 377} 378 379static void btavrcp_play_position_changed_callback(bt_bdaddr_t *bd_addr, uint32_t song_len, 380 uint32_t song_pos) { 381 382 jbyteArray addr; 383 ALOGI("%s", __FUNCTION__); 384 385 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 386 if ((!addr)) { 387 ALOGE("Fail to get new array "); 388 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 389 return; 390 } 391 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr); 392 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handleplaypositionchanged, addr, 393 (jint)(song_len), (jint)song_pos); 394 sCallbackEnv->DeleteLocalRef(addr); 395} 396 397static void btavrcp_play_status_changed_callback(bt_bdaddr_t *bd_addr, 398 btrc_play_status_t play_status) { 399 jbyteArray addr; 400 ALOGI("%s", __FUNCTION__); 401 402 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 403 if ((!addr)) { 404 ALOGE("Fail to get new array "); 405 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 406 return; 407 } 408 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr); 409 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handleplaystatuschanged, addr, 410 (jbyte)play_status); 411 sCallbackEnv->DeleteLocalRef(addr); 412} 413 414static btrc_ctrl_callbacks_t sBluetoothAvrcpCallbacks = { 415 sizeof(sBluetoothAvrcpCallbacks), 416 btavrcp_passthrough_response_callback, 417 btavrcp_groupnavigation_response_callback, 418 btavrcp_connection_state_callback, 419 btavrcp_get_rcfeatures_callback, 420 btavrcp_setplayerapplicationsetting_rsp_callback, 421 btavrcp_playerapplicationsetting_callback, 422 btavrcp_playerapplicationsetting_changed_callback, 423 btavrcp_set_abs_vol_cmd_callback, 424 btavrcp_register_notification_absvol_callback, 425 btavrcp_track_changed_callback, 426 btavrcp_play_position_changed_callback, 427 btavrcp_play_status_changed_callback 428}; 429 430static void classInitNative(JNIEnv* env, jclass clazz) { 431 method_handlePassthroughRsp = 432 env->GetMethodID(clazz, "handlePassthroughRsp", "(II)V"); 433 434 method_handleGroupNavigationRsp = 435 env->GetMethodID(clazz, "handleGroupNavigationRsp", "(II)V"); 436 437 method_onConnectionStateChanged = 438 env->GetMethodID(clazz, "onConnectionStateChanged", "(Z[B)V"); 439 440 method_getRcFeatures = 441 env->GetMethodID(clazz, "getRcFeatures", "([BI)V"); 442 443 method_setplayerappsettingrsp = 444 env->GetMethodID(clazz, "setPlayerAppSettingRsp", "([BB)V"); 445 446 method_handleplayerappsetting = 447 env->GetMethodID(clazz, "handlePlayerAppSetting", "([B[BI)V"); 448 449 method_handleplayerappsettingchanged = 450 env->GetMethodID(clazz, "onPlayerAppSettingChanged", "([B[BI)V"); 451 452 method_handleSetAbsVolume = 453 env->GetMethodID(clazz, "handleSetAbsVolume", "([BBB)V"); 454 455 method_handleRegisterNotificationAbsVol = 456 env->GetMethodID(clazz, "handleRegisterNotificationAbsVol", "([BB)V"); 457 458 method_handletrackchanged = 459 env->GetMethodID(clazz, "onTrackChanged", "([BB[I[Ljava/lang/String;)V"); 460 461 method_handleplaypositionchanged = 462 env->GetMethodID(clazz, "onPlayPositionChanged", "([BII)V"); 463 464 method_handleplaystatuschanged = 465 env->GetMethodID(clazz, "onPlayStatusChanged", "([BB)V"); 466 ALOGI("%s: succeeds", __FUNCTION__); 467} 468 469static void initNative(JNIEnv *env, jobject object) { 470 const bt_interface_t* btInf; 471 bt_status_t status; 472 473 if ( (btInf = getBluetoothInterface()) == NULL) { 474 ALOGE("Bluetooth module is not loaded"); 475 return; 476 } 477 478 if (sBluetoothAvrcpInterface !=NULL) { 479 ALOGW("Cleaning up Avrcp Interface before initializing..."); 480 sBluetoothAvrcpInterface->cleanup(); 481 sBluetoothAvrcpInterface = NULL; 482 } 483 484 if (mCallbacksObj != NULL) { 485 ALOGW("Cleaning up Avrcp callback object"); 486 env->DeleteGlobalRef(mCallbacksObj); 487 mCallbacksObj = NULL; 488 } 489 490 if ( (sBluetoothAvrcpInterface = (btrc_ctrl_interface_t *) 491 btInf->get_profile_interface(BT_PROFILE_AV_RC_CTRL_ID)) == NULL) { 492 ALOGE("Failed to get Bluetooth Avrcp Controller Interface"); 493 return; 494 } 495 496 if ( (status = sBluetoothAvrcpInterface->init(&sBluetoothAvrcpCallbacks)) != 497 BT_STATUS_SUCCESS) { 498 ALOGE("Failed to initialize Bluetooth Avrcp Controller, status: %d", status); 499 sBluetoothAvrcpInterface = NULL; 500 return; 501 } 502 503 mCallbacksObj = env->NewGlobalRef(object); 504} 505 506static void cleanupNative(JNIEnv *env, jobject object) { 507 const bt_interface_t* btInf; 508 509 if ( (btInf = getBluetoothInterface()) == NULL) { 510 ALOGE("Bluetooth module is not loaded"); 511 return; 512 } 513 514 if (sBluetoothAvrcpInterface !=NULL) { 515 sBluetoothAvrcpInterface->cleanup(); 516 sBluetoothAvrcpInterface = NULL; 517 } 518 519 if (mCallbacksObj != NULL) { 520 env->DeleteGlobalRef(mCallbacksObj); 521 mCallbacksObj = NULL; 522 } 523} 524 525static jboolean sendPassThroughCommandNative(JNIEnv *env, jobject object, jbyteArray address, 526 jint key_code, jint key_state) { 527 jbyte *addr; 528 bt_status_t status; 529 530 if (!sBluetoothAvrcpInterface) return JNI_FALSE; 531 532 ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface); 533 534 ALOGI("key_code: %d, key_state: %d", key_code, key_state); 535 536 addr = env->GetByteArrayElements(address, NULL); 537 if (!addr) { 538 jniThrowIOException(env, EINVAL); 539 return JNI_FALSE; 540 } 541 542 if ((status = sBluetoothAvrcpInterface->send_pass_through_cmd((bt_bdaddr_t *)addr, 543 (uint8_t)key_code, (uint8_t)key_state))!= BT_STATUS_SUCCESS) { 544 ALOGE("Failed sending passthru command, status: %d", status); 545 } 546 env->ReleaseByteArrayElements(address, addr, 0); 547 548 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 549} 550 551static jboolean sendGroupNavigationCommandNative(JNIEnv *env, jobject object, jbyteArray address, 552 jint key_code, jint key_state) { 553 jbyte *addr; 554 bt_status_t status; 555 556 if (!sBluetoothAvrcpInterface) return JNI_FALSE; 557 558 ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface); 559 560 ALOGI("key_code: %d, key_state: %d", key_code, key_state); 561 562 addr = env->GetByteArrayElements(address, NULL); 563 if (!addr) { 564 jniThrowIOException(env, EINVAL); 565 return JNI_FALSE; 566 } 567 568 if ((status = sBluetoothAvrcpInterface->send_group_navigation_cmd((bt_bdaddr_t *)addr, 569 (uint8_t)key_code, (uint8_t)key_state))!= BT_STATUS_SUCCESS) { 570 ALOGE("Failed sending Grp Navigation command, status: %d", status); 571 } 572 env->ReleaseByteArrayElements(address, addr, 0); 573 574 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 575} 576 577static void setPlayerApplicationSettingValuesNative(JNIEnv *env, jobject object, jbyteArray address, 578 jbyte num_attrib, jbyteArray attrib_ids, 579 jbyteArray attrib_val) { 580 bt_status_t status; 581 jbyte *addr; 582 uint8_t *pAttrs = NULL; 583 uint8_t *pAttrsVal = NULL; 584 int i; 585 jbyte *attr; 586 jbyte *attr_val; 587 588 if (!sBluetoothAvrcpInterface) return; 589 590 addr = env->GetByteArrayElements(address, NULL); 591 if (!addr) { 592 jniThrowIOException(env, EINVAL); 593 return; 594 } 595 596 pAttrs = new uint8_t[num_attrib]; 597 pAttrsVal = new uint8_t[num_attrib]; 598 if ((!pAttrs) ||(!pAttrsVal)) { 599 delete[] pAttrs; 600 ALOGE("setPlayerApplicationSettingValuesNative: not have enough memeory"); 601 return; 602 } 603 attr = env->GetByteArrayElements(attrib_ids, NULL); 604 attr_val = env->GetByteArrayElements(attrib_val, NULL); 605 if ((!attr)||(!attr_val)) { 606 delete[] pAttrs; 607 delete[] pAttrsVal; 608 jniThrowIOException(env, EINVAL); 609 return; 610 } 611 for (i = 0; i < num_attrib; ++i) { 612 pAttrs[i] = (uint8_t)attr[i]; 613 pAttrsVal[i] = (uint8_t)attr_val[i]; 614 } 615 if (i < num_attrib) { 616 delete[] pAttrs; 617 delete[] pAttrsVal; 618 env->ReleaseByteArrayElements(attrib_ids, attr, 0); 619 env->ReleaseByteArrayElements(attrib_val, attr_val, 0); 620 return; 621 } 622 623 ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface); 624 if ((status = sBluetoothAvrcpInterface->set_player_app_setting_cmd((bt_bdaddr_t *)addr, 625 (uint8_t)num_attrib, pAttrs, pAttrsVal))!= BT_STATUS_SUCCESS) { 626 ALOGE("Failed sending setPlAppSettValNative command, status: %d", status); 627 } 628 delete[] pAttrs; 629 delete[] pAttrsVal; 630 env->ReleaseByteArrayElements(attrib_ids, attr, 0); 631 env->ReleaseByteArrayElements(attrib_val, attr_val, 0); 632 env->ReleaseByteArrayElements(address, addr, 0); 633} 634 635static void sendAbsVolRspNative(JNIEnv *env, jobject object, jbyteArray address, 636 jint abs_vol, jint label) { 637 bt_status_t status; 638 jbyte *addr; 639 640 if (!sBluetoothAvrcpInterface) return; 641 addr = env->GetByteArrayElements(address, NULL); 642 if (!addr) { 643 jniThrowIOException(env, EINVAL); 644 return; 645 } 646 647 ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface); 648 if ((status = sBluetoothAvrcpInterface->set_volume_rsp((bt_bdaddr_t *)addr, 649 (uint8_t)abs_vol, (uint8_t)label))!= BT_STATUS_SUCCESS) { 650 ALOGE("Failed sending sendAbsVolRspNative command, status: %d", status); 651 } 652 env->ReleaseByteArrayElements(address, addr, 0); 653} 654 655static void sendRegisterAbsVolRspNative(JNIEnv *env, jobject object, jbyteArray address, 656 jbyte rsp_type, jint abs_vol, jint label) { 657 bt_status_t status; 658 jbyte *addr; 659 660 if (!sBluetoothAvrcpInterface) return; 661 addr = env->GetByteArrayElements(address, NULL); 662 if (!addr) { 663 jniThrowIOException(env, EINVAL); 664 return; 665 } 666 ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface); 667 if ((status = sBluetoothAvrcpInterface->register_abs_vol_rsp((bt_bdaddr_t *)addr, 668 (btrc_notification_type_t)rsp_type,(uint8_t)abs_vol, (uint8_t)label)) 669 != BT_STATUS_SUCCESS) { 670 ALOGE("Failed sending sendRegisterAbsVolRspNative command, status: %d", status); 671 } 672 env->ReleaseByteArrayElements(address, addr, 0); 673} 674 675static JNINativeMethod sMethods[] = { 676 {"classInitNative", "()V", (void *) classInitNative}, 677 {"initNative", "()V", (void *) initNative}, 678 {"cleanupNative", "()V", (void *) cleanupNative}, 679 {"sendPassThroughCommandNative", "([BII)Z",(void *) sendPassThroughCommandNative}, 680 {"sendGroupNavigationCommandNative", "([BII)Z",(void *) sendGroupNavigationCommandNative}, 681 {"setPlayerApplicationSettingValuesNative", "([BB[B[B)V", 682 (void *) setPlayerApplicationSettingValuesNative}, 683 {"sendAbsVolRspNative", "([BII)V",(void *) sendAbsVolRspNative}, 684 {"sendRegisterAbsVolRspNative", "([BBII)V",(void *) sendRegisterAbsVolRspNative}, 685}; 686 687int register_com_android_bluetooth_avrcp_controller(JNIEnv* env) 688{ 689 return jniRegisterNativeMethods(env, "com/android/bluetooth/avrcp/AvrcpControllerService", 690 sMethods, NELEM(sMethods)); 691} 692 693} 694