1 /* 2 * Copyright (C) 2016 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 "android_runtime/AndroidRuntime.h" 22 #include "com_android_bluetooth.h" 23 #include "hardware/bt_rc.h" 24 #include "utils/Log.h" 25 26 #include <string.h> 27 28 namespace android { 29 static jmethodID method_handlePassthroughRsp; 30 static jmethodID method_onConnectionStateChanged; 31 static jmethodID method_getRcFeatures; 32 static jmethodID method_setplayerappsettingrsp; 33 static jmethodID method_handleplayerappsetting; 34 static jmethodID method_handleplayerappsettingchanged; 35 static jmethodID method_handleSetAbsVolume; 36 static jmethodID method_handleRegisterNotificationAbsVol; 37 static jmethodID method_handletrackchanged; 38 static jmethodID method_handleplaypositionchanged; 39 static jmethodID method_handleplaystatuschanged; 40 static jmethodID method_handleGetFolderItemsRsp; 41 static jmethodID method_handleGetPlayerItemsRsp; 42 static jmethodID method_handleGroupNavigationRsp; 43 static jmethodID method_createFromNativeMediaItem; 44 static jmethodID method_createFromNativeFolderItem; 45 static jmethodID method_createFromNativePlayerItem; 46 static jmethodID method_handleChangeFolderRsp; 47 static jmethodID method_handleSetBrowsedPlayerRsp; 48 static jmethodID method_handleSetAddressedPlayerRsp; 49 50 static jclass class_MediaBrowser_MediaItem; 51 static jclass class_AvrcpPlayer; 52 53 static const btrc_ctrl_interface_t* sBluetoothAvrcpInterface = NULL; 54 static jobject sCallbacksObj = NULL; 55 56 static void btavrcp_passthrough_response_callback(bt_bdaddr_t* bd_addr, int id, 57 int pressed) { 58 ALOGI("%s: id: %d, pressed: %d", __func__, id, pressed); 59 CallbackEnv sCallbackEnv(__func__); 60 if (!sCallbackEnv.valid()) return; 61 62 ScopedLocalRef<jbyteArray> addr( 63 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t))); 64 if (!addr.get()) { 65 ALOGE("Fail to new jbyteArray bd addr for passthrough response"); 66 return; 67 } 68 69 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t), 70 (jbyte*)bd_addr); 71 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handlePassthroughRsp, 72 (jint)id, (jint)pressed, addr.get()); 73 } 74 75 static void btavrcp_groupnavigation_response_callback(int id, int pressed) { 76 ALOGV("%s", __func__); 77 CallbackEnv sCallbackEnv(__func__); 78 if (!sCallbackEnv.valid()) return; 79 80 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleGroupNavigationRsp, 81 (jint)id, (jint)pressed); 82 } 83 84 static void btavrcp_connection_state_callback(bool rc_connect, bool br_connect, 85 bt_bdaddr_t* bd_addr) { 86 ALOGI("%s: conn state: rc: %d br: %d", __func__, rc_connect, br_connect); 87 CallbackEnv sCallbackEnv(__func__); 88 if (!sCallbackEnv.valid()) return; 89 90 ScopedLocalRef<jbyteArray> addr( 91 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t))); 92 if (!addr.get()) { 93 ALOGE("Fail to new jbyteArray bd addr for connection state"); 94 return; 95 } 96 97 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t), 98 (jbyte*)bd_addr); 99 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_onConnectionStateChanged, 100 (jboolean)rc_connect, (jboolean)br_connect, 101 addr.get()); 102 } 103 104 static void btavrcp_get_rcfeatures_callback(bt_bdaddr_t* bd_addr, 105 int features) { 106 ALOGV("%s", __func__); 107 CallbackEnv sCallbackEnv(__func__); 108 if (!sCallbackEnv.valid()) return; 109 110 ScopedLocalRef<jbyteArray> addr( 111 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t))); 112 if (!addr.get()) { 113 ALOGE("Fail to new jbyteArray bd addr "); 114 return; 115 } 116 117 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t), 118 (jbyte*)bd_addr); 119 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_getRcFeatures, addr.get(), 120 (jint)features); 121 } 122 123 static void btavrcp_setplayerapplicationsetting_rsp_callback( 124 bt_bdaddr_t* bd_addr, uint8_t accepted) { 125 ALOGV("%s", __func__); 126 CallbackEnv sCallbackEnv(__func__); 127 if (!sCallbackEnv.valid()) return; 128 129 ScopedLocalRef<jbyteArray> addr( 130 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t))); 131 if (!addr.get()) { 132 ALOGE("Fail to new jbyteArray bd addr "); 133 return; 134 } 135 136 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t), 137 (jbyte*)bd_addr); 138 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_setplayerappsettingrsp, 139 addr.get(), (jint)accepted); 140 } 141 142 static void btavrcp_playerapplicationsetting_callback( 143 bt_bdaddr_t* bd_addr, uint8_t num_attr, btrc_player_app_attr_t* app_attrs, 144 uint8_t num_ext_attr, btrc_player_app_ext_attr_t* ext_attrs) { 145 ALOGI("%s", __func__); 146 CallbackEnv sCallbackEnv(__func__); 147 if (!sCallbackEnv.valid()) return; 148 149 ScopedLocalRef<jbyteArray> addr( 150 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t))); 151 if (!addr.get()) { 152 ALOGE("Fail to new jbyteArray bd addr "); 153 return; 154 } 155 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t), 156 (jbyte*)bd_addr); 157 /* TODO ext attrs 158 * Flattening defined attributes: <id,num_values,values[]> 159 */ 160 jint arraylen = 0; 161 for (int i = 0; i < num_attr; i++) { 162 /*2 bytes for id and num */ 163 arraylen += 2 + app_attrs[i].num_val; 164 } 165 ALOGV(" arraylen %d", arraylen); 166 167 ScopedLocalRef<jbyteArray> playerattribs( 168 sCallbackEnv.get(), sCallbackEnv->NewByteArray(arraylen)); 169 if (!playerattribs.get()) { 170 ALOGE("Fail to new jbyteArray playerattribs "); 171 return; 172 } 173 174 for (int i = 0, k = 0; (i < num_attr) && (k < arraylen); i++) { 175 sCallbackEnv->SetByteArrayRegion(playerattribs.get(), k, 1, 176 (jbyte*)&(app_attrs[i].attr_id)); 177 k++; 178 sCallbackEnv->SetByteArrayRegion(playerattribs.get(), k, 1, 179 (jbyte*)&(app_attrs[i].num_val)); 180 k++; 181 sCallbackEnv->SetByteArrayRegion(playerattribs.get(), k, 182 app_attrs[i].num_val, 183 (jbyte*)(app_attrs[i].attr_val)); 184 k = k + app_attrs[i].num_val; 185 } 186 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleplayerappsetting, 187 addr.get(), playerattribs.get(), (jint)arraylen); 188 } 189 190 static void btavrcp_playerapplicationsetting_changed_callback( 191 bt_bdaddr_t* bd_addr, btrc_player_settings_t* p_vals) { 192 ALOGI("%s", __func__); 193 CallbackEnv sCallbackEnv(__func__); 194 if (!sCallbackEnv.valid()) return; 195 196 ScopedLocalRef<jbyteArray> addr( 197 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t))); 198 if (!addr.get()) { 199 ALOGE("Fail to get new array "); 200 return; 201 } 202 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t), 203 (jbyte*)bd_addr); 204 205 int arraylen = p_vals->num_attr * 2; 206 ScopedLocalRef<jbyteArray> playerattribs( 207 sCallbackEnv.get(), sCallbackEnv->NewByteArray(arraylen)); 208 if (!playerattribs.get()) { 209 ALOGE("Fail to new jbyteArray playerattribs "); 210 return; 211 } 212 /* 213 * Flatening format: <id,val> 214 */ 215 for (int i = 0, k = 0; (i < p_vals->num_attr) && (k < arraylen); i++) { 216 sCallbackEnv->SetByteArrayRegion(playerattribs.get(), k, 1, 217 (jbyte*)&(p_vals->attr_ids[i])); 218 k++; 219 sCallbackEnv->SetByteArrayRegion(playerattribs.get(), k, 1, 220 (jbyte*)&(p_vals->attr_values[i])); 221 k++; 222 } 223 sCallbackEnv->CallVoidMethod(sCallbacksObj, 224 method_handleplayerappsettingchanged, addr.get(), 225 playerattribs.get(), (jint)arraylen); 226 } 227 228 static void btavrcp_set_abs_vol_cmd_callback(bt_bdaddr_t* bd_addr, 229 uint8_t abs_vol, uint8_t label) { 230 ALOGI("%s", __func__); 231 CallbackEnv sCallbackEnv(__func__); 232 if (!sCallbackEnv.valid()) return; 233 234 ScopedLocalRef<jbyteArray> addr( 235 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t))); 236 if (!addr.get()) { 237 ALOGE("Fail to get new array "); 238 return; 239 } 240 241 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t), 242 (jbyte*)bd_addr); 243 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleSetAbsVolume, 244 addr.get(), (jbyte)abs_vol, (jbyte)label); 245 } 246 247 static void btavrcp_register_notification_absvol_callback(bt_bdaddr_t* bd_addr, 248 uint8_t label) { 249 ALOGI("%s", __func__); 250 CallbackEnv sCallbackEnv(__func__); 251 if (!sCallbackEnv.valid()) return; 252 253 ScopedLocalRef<jbyteArray> addr( 254 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t))); 255 if (!addr.get()) { 256 ALOGE("Fail to get new array "); 257 return; 258 } 259 260 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t), 261 (jbyte*)bd_addr); 262 sCallbackEnv->CallVoidMethod(sCallbacksObj, 263 method_handleRegisterNotificationAbsVol, 264 addr.get(), (jbyte)label); 265 } 266 267 static void btavrcp_track_changed_callback(bt_bdaddr_t* bd_addr, 268 uint8_t num_attr, 269 btrc_element_attr_val_t* p_attrs) { 270 /* 271 * byteArray will be formatted like this: id,len,string 272 * Assuming text feild to be null terminated. 273 */ 274 ALOGI("%s", __func__); 275 CallbackEnv sCallbackEnv(__func__); 276 if (!sCallbackEnv.valid()) return; 277 278 ScopedLocalRef<jbyteArray> addr( 279 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t))); 280 if (!addr.get()) { 281 ALOGE("Fail to get new array "); 282 return; 283 } 284 285 ScopedLocalRef<jintArray> attribIds(sCallbackEnv.get(), 286 sCallbackEnv->NewIntArray(num_attr)); 287 if (!attribIds.get()) { 288 ALOGE(" failed to set new array for attribIds"); 289 return; 290 } 291 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t), 292 (jbyte*)bd_addr); 293 294 jclass strclazz = sCallbackEnv->FindClass("java/lang/String"); 295 ScopedLocalRef<jobjectArray> stringArray( 296 sCallbackEnv.get(), 297 sCallbackEnv->NewObjectArray((jint)num_attr, strclazz, 0)); 298 if (!stringArray.get()) { 299 ALOGE(" failed to get String array"); 300 return; 301 } 302 303 for (jint i = 0; i < num_attr; i++) { 304 ScopedLocalRef<jstring> str( 305 sCallbackEnv.get(), 306 sCallbackEnv->NewStringUTF((char*)(p_attrs[i].text))); 307 if (!str.get()) { 308 ALOGE("Unable to get str"); 309 return; 310 } 311 sCallbackEnv->SetIntArrayRegion(attribIds.get(), i, 1, 312 (jint*)&(p_attrs[i].attr_id)); 313 sCallbackEnv->SetObjectArrayElement(stringArray.get(), i, str.get()); 314 } 315 316 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handletrackchanged, 317 addr.get(), (jbyte)(num_attr), attribIds.get(), 318 stringArray.get()); 319 } 320 321 static void btavrcp_play_position_changed_callback(bt_bdaddr_t* bd_addr, 322 uint32_t song_len, 323 uint32_t song_pos) { 324 ALOGI("%s", __func__); 325 CallbackEnv sCallbackEnv(__func__); 326 if (!sCallbackEnv.valid()) return; 327 328 ScopedLocalRef<jbyteArray> addr( 329 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t))); 330 if (!addr.get()) { 331 ALOGE("Fail to get new array "); 332 return; 333 } 334 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t), 335 (jbyte*)bd_addr); 336 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleplaypositionchanged, 337 addr.get(), (jint)(song_len), (jint)song_pos); 338 } 339 340 static void btavrcp_play_status_changed_callback( 341 bt_bdaddr_t* bd_addr, btrc_play_status_t play_status) { 342 ALOGI("%s", __func__); 343 CallbackEnv sCallbackEnv(__func__); 344 if (!sCallbackEnv.valid()) return; 345 346 ScopedLocalRef<jbyteArray> addr( 347 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t))); 348 if (!addr.get()) { 349 ALOGE("Fail to get new array "); 350 return; 351 } 352 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t), 353 (jbyte*)bd_addr); 354 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleplaystatuschanged, 355 addr.get(), (jbyte)play_status); 356 } 357 358 static void btavrcp_get_folder_items_callback( 359 bt_bdaddr_t* bd_addr, btrc_status_t status, 360 const btrc_folder_items_t* folder_items, uint8_t count) { 361 /* Folder items are list of items that can be either BTRC_ITEM_PLAYER 362 * BTRC_ITEM_MEDIA, BTRC_ITEM_FOLDER. Here we translate them to their java 363 * counterparts by calling the java constructor for each of the items. 364 */ 365 ALOGV("%s count %d", __func__, count); 366 CallbackEnv sCallbackEnv(__func__); 367 if (!sCallbackEnv.valid()) return; 368 369 // Inspect if the first element is a folder/item or player listing. They are 370 // always exclusive. 371 bool isPlayerListing = 372 count > 0 && (folder_items[0].item_type == BTRC_ITEM_PLAYER); 373 374 // Initialize arrays for Folder OR Player listing. 375 ScopedLocalRef<jobjectArray> itemArray(sCallbackEnv.get(), NULL); 376 if (isPlayerListing) { 377 itemArray.reset( 378 sCallbackEnv->NewObjectArray((jint)count, class_AvrcpPlayer, 0)); 379 } else { 380 itemArray.reset(sCallbackEnv->NewObjectArray( 381 (jint)count, class_MediaBrowser_MediaItem, 0)); 382 } 383 if (!itemArray.get()) { 384 ALOGE("%s itemArray allocation failed.", __func__); 385 return; 386 } 387 for (int i = 0; i < count; i++) { 388 const btrc_folder_items_t* item = &(folder_items[i]); 389 ALOGV("%s item type %d", __func__, item->item_type); 390 switch (item->item_type) { 391 case BTRC_ITEM_MEDIA: { 392 // Parse name 393 ScopedLocalRef<jstring> mediaName( 394 sCallbackEnv.get(), 395 sCallbackEnv->NewStringUTF((const char*)item->media.name)); 396 if (!mediaName.get()) { 397 ALOGE("%s can't allocate media name string!", __func__); 398 return; 399 } 400 // Parse UID 401 ScopedLocalRef<jbyteArray> uidByteArray( 402 sCallbackEnv.get(), 403 sCallbackEnv->NewByteArray(sizeof(uint8_t) * BTRC_UID_SIZE)); 404 if (!uidByteArray.get()) { 405 ALOGE("%s can't allocate uid array!", __func__); 406 return; 407 } 408 sCallbackEnv->SetByteArrayRegion(uidByteArray.get(), 0, 409 BTRC_UID_SIZE * sizeof(uint8_t), 410 (jbyte*)item->media.uid); 411 412 // Parse Attrs 413 ScopedLocalRef<jintArray> attrIdArray( 414 sCallbackEnv.get(), 415 sCallbackEnv->NewIntArray(item->media.num_attrs)); 416 if (!attrIdArray.get()) { 417 ALOGE("%s can't allocate attr id array!", __func__); 418 return; 419 } 420 ScopedLocalRef<jobjectArray> attrValArray( 421 sCallbackEnv.get(), 422 sCallbackEnv->NewObjectArray( 423 item->media.num_attrs, 424 sCallbackEnv->FindClass("java/lang/String"), 0)); 425 if (!attrValArray.get()) { 426 ALOGE("%s can't allocate attr val array!", __func__); 427 return; 428 } 429 430 for (int j = 0; j < item->media.num_attrs; j++) { 431 sCallbackEnv->SetIntArrayRegion( 432 attrIdArray.get(), j, 1, 433 (jint*)&(item->media.p_attrs[j].attr_id)); 434 ScopedLocalRef<jstring> attrValStr( 435 sCallbackEnv.get(), 436 sCallbackEnv->NewStringUTF((char*)(item->media.p_attrs[j].text))); 437 if (!uidByteArray.get()) { 438 ALOGE("%s can't allocate uid array!", __func__); 439 return; 440 } 441 sCallbackEnv->SetObjectArrayElement(attrValArray.get(), j, 442 attrValStr.get()); 443 } 444 445 ScopedLocalRef<jobject> mediaObj( 446 sCallbackEnv.get(), 447 (jobject)sCallbackEnv->CallObjectMethod( 448 sCallbacksObj, method_createFromNativeMediaItem, 449 uidByteArray.get(), (jint)item->media.type, mediaName.get(), 450 attrIdArray.get(), attrValArray.get())); 451 if (!mediaObj.get()) { 452 ALOGE("%s failed to creae MediaItem for type ITEM_MEDIA", __func__); 453 return; 454 } 455 sCallbackEnv->SetObjectArrayElement(itemArray.get(), i, mediaObj.get()); 456 break; 457 } 458 459 case BTRC_ITEM_FOLDER: { 460 // Parse name 461 ScopedLocalRef<jstring> folderName( 462 sCallbackEnv.get(), 463 sCallbackEnv->NewStringUTF((const char*)item->folder.name)); 464 if (!folderName.get()) { 465 ALOGE("%s can't allocate folder name string!", __func__); 466 return; 467 } 468 // Parse UID 469 ScopedLocalRef<jbyteArray> uidByteArray( 470 sCallbackEnv.get(), 471 sCallbackEnv->NewByteArray(sizeof(uint8_t) * BTRC_UID_SIZE)); 472 if (!uidByteArray.get()) { 473 ALOGE("%s can't allocate uid array!", __func__); 474 return; 475 } 476 sCallbackEnv->SetByteArrayRegion(uidByteArray.get(), 0, 477 BTRC_UID_SIZE * sizeof(uint8_t), 478 (jbyte*)item->folder.uid); 479 480 ScopedLocalRef<jobject> folderObj( 481 sCallbackEnv.get(), 482 (jobject)sCallbackEnv->CallObjectMethod( 483 sCallbacksObj, method_createFromNativeFolderItem, 484 uidByteArray.get(), (jint)item->folder.type, folderName.get(), 485 (jint)item->folder.playable)); 486 if (!folderObj.get()) { 487 ALOGE("%s failed to create MediaItem for type ITEM_FOLDER", __func__); 488 return; 489 } 490 sCallbackEnv->SetObjectArrayElement(itemArray.get(), i, 491 folderObj.get()); 492 break; 493 } 494 495 case BTRC_ITEM_PLAYER: { 496 // Parse name 497 isPlayerListing = true; 498 jint id = (jint)item->player.player_id; 499 jint playerType = (jint)item->player.major_type; 500 jint playStatus = (jint)item->player.play_status; 501 ScopedLocalRef<jbyteArray> featureBitArray( 502 sCallbackEnv.get(), 503 sCallbackEnv->NewByteArray(BTRC_FEATURE_BIT_MASK_SIZE * 504 sizeof(uint8_t))); 505 if (!featureBitArray.get()) { 506 ALOGE("%s failed to allocate featureBitArray", __func__); 507 return; 508 } 509 sCallbackEnv->SetByteArrayRegion( 510 featureBitArray.get(), 0, 511 sizeof(uint8_t) * BTRC_FEATURE_BIT_MASK_SIZE, 512 (jbyte*)item->player.features); 513 ScopedLocalRef<jstring> playerName( 514 sCallbackEnv.get(), 515 sCallbackEnv->NewStringUTF((const char*)item->player.name)); 516 if (!playerName.get()) { 517 ALOGE("%s can't allocate player name string!", __func__); 518 return; 519 } 520 ScopedLocalRef<jobject> playerObj( 521 sCallbackEnv.get(), 522 (jobject)sCallbackEnv->CallObjectMethod( 523 sCallbacksObj, method_createFromNativePlayerItem, id, 524 playerName.get(), featureBitArray.get(), playStatus, 525 playerType)); 526 if (!playerObj.get()) { 527 ALOGE("%s failed to create AvrcpPlayer from ITEM_PLAYER", __func__); 528 return; 529 } 530 sCallbackEnv->SetObjectArrayElement(itemArray.get(), i, 531 playerObj.get()); 532 break; 533 } 534 535 default: 536 ALOGE("%s cannot understand type %d", __func__, item->item_type); 537 } 538 } 539 540 if (isPlayerListing) { 541 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleGetPlayerItemsRsp, 542 itemArray.get()); 543 } else { 544 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleGetFolderItemsRsp, 545 status, itemArray.get()); 546 } 547 } 548 549 static void btavrcp_change_path_callback(bt_bdaddr_t* bd_addr, uint8_t count) { 550 ALOGI("%s count %d", __func__, count); 551 CallbackEnv sCallbackEnv(__func__); 552 if (!sCallbackEnv.valid()) return; 553 554 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleChangeFolderRsp, 555 (jint)count); 556 } 557 558 static void btavrcp_set_browsed_player_callback(bt_bdaddr_t* bd_addr, 559 uint8_t num_items, 560 uint8_t depth) { 561 ALOGI("%s items %d depth %d", __func__, num_items, depth); 562 CallbackEnv sCallbackEnv(__func__); 563 if (!sCallbackEnv.valid()) return; 564 565 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleSetBrowsedPlayerRsp, 566 (jint)num_items, (jint)depth); 567 } 568 569 static void btavrcp_set_addressed_player_callback(bt_bdaddr_t* bd_addr, 570 uint8_t status) { 571 ALOGI("%s status %d", __func__, status); 572 573 CallbackEnv sCallbackEnv(__func__); 574 if (!sCallbackEnv.valid()) return; 575 576 sCallbackEnv->CallVoidMethod( 577 sCallbacksObj, method_handleSetAddressedPlayerRsp, (jint)status); 578 } 579 580 static btrc_ctrl_callbacks_t sBluetoothAvrcpCallbacks = { 581 sizeof(sBluetoothAvrcpCallbacks), 582 btavrcp_passthrough_response_callback, 583 btavrcp_groupnavigation_response_callback, 584 btavrcp_connection_state_callback, 585 btavrcp_get_rcfeatures_callback, 586 btavrcp_setplayerapplicationsetting_rsp_callback, 587 btavrcp_playerapplicationsetting_callback, 588 btavrcp_playerapplicationsetting_changed_callback, 589 btavrcp_set_abs_vol_cmd_callback, 590 btavrcp_register_notification_absvol_callback, 591 btavrcp_track_changed_callback, 592 btavrcp_play_position_changed_callback, 593 btavrcp_play_status_changed_callback, 594 btavrcp_get_folder_items_callback, 595 btavrcp_change_path_callback, 596 btavrcp_set_browsed_player_callback, 597 btavrcp_set_addressed_player_callback}; 598 599 static void classInitNative(JNIEnv* env, jclass clazz) { 600 method_handlePassthroughRsp = 601 env->GetMethodID(clazz, "handlePassthroughRsp", "(II[B)V"); 602 603 method_handleGroupNavigationRsp = 604 env->GetMethodID(clazz, "handleGroupNavigationRsp", "(II)V"); 605 606 method_onConnectionStateChanged = 607 env->GetMethodID(clazz, "onConnectionStateChanged", "(ZZ[B)V"); 608 609 method_getRcFeatures = env->GetMethodID(clazz, "getRcFeatures", "([BI)V"); 610 611 method_setplayerappsettingrsp = 612 env->GetMethodID(clazz, "setPlayerAppSettingRsp", "([BB)V"); 613 614 method_handleplayerappsetting = 615 env->GetMethodID(clazz, "handlePlayerAppSetting", "([B[BI)V"); 616 617 method_handleplayerappsettingchanged = 618 env->GetMethodID(clazz, "onPlayerAppSettingChanged", "([B[BI)V"); 619 620 method_handleSetAbsVolume = 621 env->GetMethodID(clazz, "handleSetAbsVolume", "([BBB)V"); 622 623 method_handleRegisterNotificationAbsVol = 624 env->GetMethodID(clazz, "handleRegisterNotificationAbsVol", "([BB)V"); 625 626 method_handletrackchanged = 627 env->GetMethodID(clazz, "onTrackChanged", "([BB[I[Ljava/lang/String;)V"); 628 629 method_handleplaypositionchanged = 630 env->GetMethodID(clazz, "onPlayPositionChanged", "([BII)V"); 631 632 method_handleplaystatuschanged = 633 env->GetMethodID(clazz, "onPlayStatusChanged", "([BB)V"); 634 635 method_handleGetFolderItemsRsp = 636 env->GetMethodID(clazz, "handleGetFolderItemsRsp", 637 "(I[Landroid/media/browse/MediaBrowser$MediaItem;)V"); 638 method_handleGetPlayerItemsRsp = env->GetMethodID( 639 clazz, "handleGetPlayerItemsRsp", 640 "([Lcom/android/bluetooth/avrcpcontroller/AvrcpPlayer;)V"); 641 642 method_createFromNativeMediaItem = 643 env->GetMethodID(clazz, "createFromNativeMediaItem", 644 "([BILjava/lang/String;[I[Ljava/lang/String;)Landroid/" 645 "media/browse/MediaBrowser$MediaItem;"); 646 method_createFromNativeFolderItem = env->GetMethodID( 647 clazz, "createFromNativeFolderItem", 648 "([BILjava/lang/String;I)Landroid/media/browse/MediaBrowser$MediaItem;"); 649 method_createFromNativePlayerItem = 650 env->GetMethodID(clazz, "createFromNativePlayerItem", 651 "(ILjava/lang/String;[BII)Lcom/android/bluetooth/" 652 "avrcpcontroller/AvrcpPlayer;"); 653 method_handleChangeFolderRsp = 654 env->GetMethodID(clazz, "handleChangeFolderRsp", "(I)V"); 655 method_handleSetBrowsedPlayerRsp = 656 env->GetMethodID(clazz, "handleSetBrowsedPlayerRsp", "(II)V"); 657 method_handleSetAddressedPlayerRsp = 658 env->GetMethodID(clazz, "handleSetAddressedPlayerRsp", "(I)V"); 659 ALOGI("%s: succeeds", __func__); 660 } 661 662 static void initNative(JNIEnv* env, jobject object) { 663 jclass tmpMediaItem = 664 env->FindClass("android/media/browse/MediaBrowser$MediaItem"); 665 class_MediaBrowser_MediaItem = (jclass)env->NewGlobalRef(tmpMediaItem); 666 667 jclass tmpBtPlayer = 668 env->FindClass("com/android/bluetooth/avrcpcontroller/AvrcpPlayer"); 669 class_AvrcpPlayer = (jclass)env->NewGlobalRef(tmpBtPlayer); 670 671 const bt_interface_t* btInf = getBluetoothInterface(); 672 if (btInf == NULL) { 673 ALOGE("Bluetooth module is not loaded"); 674 return; 675 } 676 677 if (sBluetoothAvrcpInterface != NULL) { 678 ALOGW("Cleaning up Avrcp Interface before initializing..."); 679 sBluetoothAvrcpInterface->cleanup(); 680 sBluetoothAvrcpInterface = NULL; 681 } 682 683 if (sCallbacksObj != NULL) { 684 ALOGW("Cleaning up Avrcp callback object"); 685 env->DeleteGlobalRef(sCallbacksObj); 686 sCallbacksObj = NULL; 687 } 688 689 sBluetoothAvrcpInterface = 690 (btrc_ctrl_interface_t*)btInf->get_profile_interface( 691 BT_PROFILE_AV_RC_CTRL_ID); 692 if (sBluetoothAvrcpInterface == NULL) { 693 ALOGE("Failed to get Bluetooth Avrcp Controller Interface"); 694 return; 695 } 696 697 bt_status_t status = 698 sBluetoothAvrcpInterface->init(&sBluetoothAvrcpCallbacks); 699 if (status != BT_STATUS_SUCCESS) { 700 ALOGE("Failed to initialize Bluetooth Avrcp Controller, status: %d", 701 status); 702 sBluetoothAvrcpInterface = NULL; 703 return; 704 } 705 706 sCallbacksObj = env->NewGlobalRef(object); 707 } 708 709 static void cleanupNative(JNIEnv* env, jobject object) { 710 const bt_interface_t* btInf = getBluetoothInterface(); 711 if (btInf == NULL) { 712 ALOGE("Bluetooth module is not loaded"); 713 return; 714 } 715 716 if (sBluetoothAvrcpInterface != NULL) { 717 sBluetoothAvrcpInterface->cleanup(); 718 sBluetoothAvrcpInterface = NULL; 719 } 720 721 if (sCallbacksObj != NULL) { 722 env->DeleteGlobalRef(sCallbacksObj); 723 sCallbacksObj = NULL; 724 } 725 } 726 727 static jboolean sendPassThroughCommandNative(JNIEnv* env, jobject object, 728 jbyteArray address, jint key_code, 729 jint key_state) { 730 if (!sBluetoothAvrcpInterface) return JNI_FALSE; 731 732 ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface); 733 734 ALOGI("key_code: %d, key_state: %d", key_code, key_state); 735 736 jbyte* addr = env->GetByteArrayElements(address, NULL); 737 if (!addr) { 738 jniThrowIOException(env, EINVAL); 739 return JNI_FALSE; 740 } 741 742 bt_status_t status = sBluetoothAvrcpInterface->send_pass_through_cmd( 743 (bt_bdaddr_t*)addr, (uint8_t)key_code, (uint8_t)key_state); 744 if (status != BT_STATUS_SUCCESS) { 745 ALOGE("Failed sending passthru command, status: %d", status); 746 } 747 env->ReleaseByteArrayElements(address, addr, 0); 748 749 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 750 } 751 752 static jboolean sendGroupNavigationCommandNative(JNIEnv* env, jobject object, 753 jbyteArray address, 754 jint key_code, 755 jint key_state) { 756 if (!sBluetoothAvrcpInterface) return JNI_FALSE; 757 758 ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface); 759 760 ALOGI("key_code: %d, key_state: %d", key_code, key_state); 761 762 jbyte* addr = env->GetByteArrayElements(address, NULL); 763 if (!addr) { 764 jniThrowIOException(env, EINVAL); 765 return JNI_FALSE; 766 } 767 768 bt_status_t status = sBluetoothAvrcpInterface->send_group_navigation_cmd( 769 (bt_bdaddr_t*)addr, (uint8_t)key_code, (uint8_t)key_state); 770 if (status != BT_STATUS_SUCCESS) { 771 ALOGE("Failed sending Grp Navigation command, status: %d", status); 772 } 773 env->ReleaseByteArrayElements(address, addr, 0); 774 775 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 776 } 777 778 static void setPlayerApplicationSettingValuesNative(JNIEnv* env, jobject object, 779 jbyteArray address, 780 jbyte num_attrib, 781 jbyteArray attrib_ids, 782 jbyteArray attrib_val) { 783 ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface); 784 if (!sBluetoothAvrcpInterface) return; 785 786 jbyte* addr = env->GetByteArrayElements(address, NULL); 787 if (!addr) { 788 jniThrowIOException(env, EINVAL); 789 return; 790 } 791 792 uint8_t* pAttrs = new uint8_t[num_attrib]; 793 uint8_t* pAttrsVal = new uint8_t[num_attrib]; 794 if ((!pAttrs) || (!pAttrsVal)) { 795 delete[] pAttrs; 796 ALOGE("setPlayerApplicationSettingValuesNative: not have enough memeory"); 797 return; 798 } 799 800 jbyte* attr = env->GetByteArrayElements(attrib_ids, NULL); 801 jbyte* attr_val = env->GetByteArrayElements(attrib_val, NULL); 802 if ((!attr) || (!attr_val)) { 803 delete[] pAttrs; 804 delete[] pAttrsVal; 805 jniThrowIOException(env, EINVAL); 806 return; 807 } 808 809 int i; 810 for (i = 0; i < num_attrib; ++i) { 811 pAttrs[i] = (uint8_t)attr[i]; 812 pAttrsVal[i] = (uint8_t)attr_val[i]; 813 } 814 815 bt_status_t status = sBluetoothAvrcpInterface->set_player_app_setting_cmd( 816 (bt_bdaddr_t*)addr, (uint8_t)num_attrib, pAttrs, pAttrsVal); 817 if (status != BT_STATUS_SUCCESS) { 818 ALOGE("Failed sending setPlAppSettValNative command, status: %d", status); 819 } 820 delete[] pAttrs; 821 delete[] pAttrsVal; 822 env->ReleaseByteArrayElements(attrib_ids, attr, 0); 823 env->ReleaseByteArrayElements(attrib_val, attr_val, 0); 824 env->ReleaseByteArrayElements(address, addr, 0); 825 } 826 827 static void sendAbsVolRspNative(JNIEnv* env, jobject object, jbyteArray address, 828 jint abs_vol, jint label) { 829 if (!sBluetoothAvrcpInterface) return; 830 831 jbyte* addr = env->GetByteArrayElements(address, NULL); 832 if (!addr) { 833 jniThrowIOException(env, EINVAL); 834 return; 835 } 836 837 ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface); 838 bt_status_t status = sBluetoothAvrcpInterface->set_volume_rsp( 839 (bt_bdaddr_t*)addr, (uint8_t)abs_vol, (uint8_t)label); 840 if (status != BT_STATUS_SUCCESS) { 841 ALOGE("Failed sending sendAbsVolRspNative command, status: %d", status); 842 } 843 env->ReleaseByteArrayElements(address, addr, 0); 844 } 845 846 static void sendRegisterAbsVolRspNative(JNIEnv* env, jobject object, 847 jbyteArray address, jbyte rsp_type, 848 jint abs_vol, jint label) { 849 if (!sBluetoothAvrcpInterface) return; 850 851 jbyte* addr = env->GetByteArrayElements(address, NULL); 852 if (!addr) { 853 jniThrowIOException(env, EINVAL); 854 return; 855 } 856 ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface); 857 bt_status_t status = sBluetoothAvrcpInterface->register_abs_vol_rsp( 858 (bt_bdaddr_t*)addr, (btrc_notification_type_t)rsp_type, (uint8_t)abs_vol, 859 (uint8_t)label); 860 if (status != BT_STATUS_SUCCESS) { 861 ALOGE("Failed sending sendRegisterAbsVolRspNative command, status: %d", 862 status); 863 } 864 env->ReleaseByteArrayElements(address, addr, 0); 865 } 866 867 static void getPlaybackStateNative(JNIEnv* env, jobject object, 868 jbyteArray address) { 869 if (!sBluetoothAvrcpInterface) return; 870 871 jbyte* addr = env->GetByteArrayElements(address, NULL); 872 if (!addr) { 873 jniThrowIOException(env, EINVAL); 874 return; 875 } 876 ALOGV("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface); 877 bt_status_t status = 878 sBluetoothAvrcpInterface->get_playback_state_cmd((bt_bdaddr_t*)addr); 879 if (status != BT_STATUS_SUCCESS) { 880 ALOGE("Failed sending getPlaybackStateNative command, status: %d", status); 881 } 882 env->ReleaseByteArrayElements(address, addr, 0); 883 } 884 885 static void getNowPlayingListNative(JNIEnv* env, jobject object, 886 jbyteArray address, jbyte start, 887 jbyte items) { 888 if (!sBluetoothAvrcpInterface) return; 889 jbyte* addr = env->GetByteArrayElements(address, NULL); 890 if (!addr) { 891 jniThrowIOException(env, EINVAL); 892 return; 893 } 894 ALOGV("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface); 895 bt_status_t status = sBluetoothAvrcpInterface->get_now_playing_list_cmd( 896 (bt_bdaddr_t*)addr, (uint8_t)start, (uint8_t)items); 897 if (status != BT_STATUS_SUCCESS) { 898 ALOGE("Failed sending getNowPlayingListNative command, status: %d", status); 899 } 900 env->ReleaseByteArrayElements(address, addr, 0); 901 } 902 903 static void getFolderListNative(JNIEnv* env, jobject object, jbyteArray address, 904 jbyte start, jbyte items) { 905 if (!sBluetoothAvrcpInterface) return; 906 jbyte* addr = env->GetByteArrayElements(address, NULL); 907 if (!addr) { 908 jniThrowIOException(env, EINVAL); 909 return; 910 } 911 ALOGV("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface); 912 bt_status_t status = sBluetoothAvrcpInterface->get_folder_list_cmd( 913 (bt_bdaddr_t*)addr, (uint8_t)start, (uint8_t)items); 914 if (status != BT_STATUS_SUCCESS) { 915 ALOGE("Failed sending getFolderListNative command, status: %d", status); 916 } 917 env->ReleaseByteArrayElements(address, addr, 0); 918 } 919 920 static void getPlayerListNative(JNIEnv* env, jobject object, jbyteArray address, 921 jbyte start, jbyte items) { 922 if (!sBluetoothAvrcpInterface) return; 923 jbyte* addr = env->GetByteArrayElements(address, NULL); 924 if (!addr) { 925 jniThrowIOException(env, EINVAL); 926 return; 927 } 928 ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface); 929 930 bt_status_t status = sBluetoothAvrcpInterface->get_player_list_cmd( 931 (bt_bdaddr_t*)addr, (uint8_t)start, (uint8_t)items); 932 if (status != BT_STATUS_SUCCESS) { 933 ALOGE("Failed sending getPlayerListNative command, status: %d", status); 934 } 935 env->ReleaseByteArrayElements(address, addr, 0); 936 } 937 938 static void changeFolderPathNative(JNIEnv* env, jobject object, 939 jbyteArray address, jbyte direction, 940 jbyteArray uidarr) { 941 if (!sBluetoothAvrcpInterface) return; 942 jbyte* addr = env->GetByteArrayElements(address, NULL); 943 if (!addr) { 944 jniThrowIOException(env, EINVAL); 945 return; 946 } 947 948 jbyte* uid = env->GetByteArrayElements(uidarr, NULL); 949 if (!uid) { 950 jniThrowIOException(env, EINVAL); 951 return; 952 } 953 954 ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface); 955 956 bt_status_t status = sBluetoothAvrcpInterface->change_folder_path_cmd( 957 (bt_bdaddr_t*)addr, (uint8_t)direction, (uint8_t*)uid); 958 if (status != BT_STATUS_SUCCESS) { 959 ALOGE("Failed sending changeFolderPathNative command, status: %d", status); 960 } 961 env->ReleaseByteArrayElements(address, addr, 0); 962 } 963 964 static void setBrowsedPlayerNative(JNIEnv* env, jobject object, 965 jbyteArray address, jint id) { 966 if (!sBluetoothAvrcpInterface) return; 967 jbyte* addr = env->GetByteArrayElements(address, NULL); 968 if (!addr) { 969 jniThrowIOException(env, EINVAL); 970 return; 971 } 972 973 ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface); 974 bt_status_t status = sBluetoothAvrcpInterface->set_browsed_player_cmd( 975 (bt_bdaddr_t*)addr, (uint16_t)id); 976 if (status != BT_STATUS_SUCCESS) { 977 ALOGE("Failed sending setBrowsedPlayerNative command, status: %d", status); 978 } 979 env->ReleaseByteArrayElements(address, addr, 0); 980 } 981 982 static void setAddressedPlayerNative(JNIEnv* env, jobject object, 983 jbyteArray address, jint id) { 984 if (!sBluetoothAvrcpInterface) return; 985 jbyte* addr = env->GetByteArrayElements(address, NULL); 986 if (!addr) { 987 jniThrowIOException(env, EINVAL); 988 return; 989 } 990 991 ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface); 992 bt_status_t status = sBluetoothAvrcpInterface->set_addressed_player_cmd( 993 (bt_bdaddr_t*)addr, (uint16_t)id); 994 if (status != BT_STATUS_SUCCESS) { 995 ALOGE("Failed sending setAddressedPlayerNative command, status: %d", 996 status); 997 } 998 env->ReleaseByteArrayElements(address, addr, 0); 999 } 1000 1001 static void playItemNative(JNIEnv* env, jobject object, jbyteArray address, 1002 jbyte scope, jbyteArray uidArr, jint uidCounter) { 1003 if (!sBluetoothAvrcpInterface) return; 1004 jbyte* addr = env->GetByteArrayElements(address, NULL); 1005 if (!addr) { 1006 jniThrowIOException(env, EINVAL); 1007 return; 1008 } 1009 1010 jbyte* uid = env->GetByteArrayElements(uidArr, NULL); 1011 if (!uid) { 1012 jniThrowIOException(env, EINVAL); 1013 return; 1014 } 1015 1016 ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface); 1017 bt_status_t status = sBluetoothAvrcpInterface->play_item_cmd( 1018 (bt_bdaddr_t*)addr, (uint8_t)scope, (uint8_t*)uid, (uint16_t)uidCounter); 1019 if (status != BT_STATUS_SUCCESS) { 1020 ALOGE("Failed sending playItemNative command, status: %d", status); 1021 } 1022 env->ReleaseByteArrayElements(address, addr, 0); 1023 } 1024 1025 static JNINativeMethod sMethods[] = { 1026 {"classInitNative", "()V", (void*)classInitNative}, 1027 {"initNative", "()V", (void*)initNative}, 1028 {"cleanupNative", "()V", (void*)cleanupNative}, 1029 {"sendPassThroughCommandNative", "([BII)Z", 1030 (void*)sendPassThroughCommandNative}, 1031 {"sendGroupNavigationCommandNative", "([BII)Z", 1032 (void*)sendGroupNavigationCommandNative}, 1033 {"setPlayerApplicationSettingValuesNative", "([BB[B[B)V", 1034 (void*)setPlayerApplicationSettingValuesNative}, 1035 {"sendAbsVolRspNative", "([BII)V", (void*)sendAbsVolRspNative}, 1036 {"sendRegisterAbsVolRspNative", "([BBII)V", 1037 (void*)sendRegisterAbsVolRspNative}, 1038 {"getPlaybackStateNative", "([B)V", (void*)getPlaybackStateNative}, 1039 {"getNowPlayingListNative", "([BBB)V", (void*)getNowPlayingListNative}, 1040 {"getFolderListNative", "([BBB)V", (void*)getFolderListNative}, 1041 {"getPlayerListNative", "([BBB)V", (void*)getPlayerListNative}, 1042 {"changeFolderPathNative", "([BB[B)V", (void*)changeFolderPathNative}, 1043 {"playItemNative", "([BB[BI)V", (void*)playItemNative}, 1044 {"setBrowsedPlayerNative", "([BI)V", (void*)setBrowsedPlayerNative}, 1045 {"setAddressedPlayerNative", "([BI)V", (void*)setAddressedPlayerNative}, 1046 }; 1047 1048 int register_com_android_bluetooth_avrcp_controller(JNIEnv* env) { 1049 return jniRegisterNativeMethods( 1050 env, "com/android/bluetooth/avrcpcontroller/AvrcpControllerService", 1051 sMethods, NELEM(sMethods)); 1052 } 1053 } 1054