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
btavrcp_passthrough_response_callback(bt_bdaddr_t * bd_addr,int id,int pressed)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
btavrcp_groupnavigation_response_callback(int id,int pressed)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
btavrcp_connection_state_callback(bool rc_connect,bool br_connect,bt_bdaddr_t * bd_addr)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
btavrcp_get_rcfeatures_callback(bt_bdaddr_t * bd_addr,int features)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
btavrcp_setplayerapplicationsetting_rsp_callback(bt_bdaddr_t * bd_addr,uint8_t accepted)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
btavrcp_playerapplicationsetting_callback(bt_bdaddr_t * bd_addr,uint8_t num_attr,btrc_player_app_attr_t * app_attrs,uint8_t num_ext_attr,btrc_player_app_ext_attr_t * ext_attrs)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
btavrcp_playerapplicationsetting_changed_callback(bt_bdaddr_t * bd_addr,btrc_player_settings_t * p_vals)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
btavrcp_set_abs_vol_cmd_callback(bt_bdaddr_t * bd_addr,uint8_t abs_vol,uint8_t label)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
btavrcp_register_notification_absvol_callback(bt_bdaddr_t * bd_addr,uint8_t label)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
btavrcp_track_changed_callback(bt_bdaddr_t * bd_addr,uint8_t num_attr,btrc_element_attr_val_t * p_attrs)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
btavrcp_play_position_changed_callback(bt_bdaddr_t * bd_addr,uint32_t song_len,uint32_t song_pos)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
btavrcp_play_status_changed_callback(bt_bdaddr_t * bd_addr,btrc_play_status_t play_status)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
btavrcp_get_folder_items_callback(bt_bdaddr_t * bd_addr,btrc_status_t status,const btrc_folder_items_t * folder_items,uint8_t count)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
btavrcp_change_path_callback(bt_bdaddr_t * bd_addr,uint8_t count)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
btavrcp_set_browsed_player_callback(bt_bdaddr_t * bd_addr,uint8_t num_items,uint8_t depth)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
btavrcp_set_addressed_player_callback(bt_bdaddr_t * bd_addr,uint8_t status)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
classInitNative(JNIEnv * env,jclass clazz)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
initNative(JNIEnv * env,jobject object)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
cleanupNative(JNIEnv * env,jobject object)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
sendPassThroughCommandNative(JNIEnv * env,jobject object,jbyteArray address,jint key_code,jint key_state)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
sendGroupNavigationCommandNative(JNIEnv * env,jobject object,jbyteArray address,jint key_code,jint key_state)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
setPlayerApplicationSettingValuesNative(JNIEnv * env,jobject object,jbyteArray address,jbyte num_attrib,jbyteArray attrib_ids,jbyteArray attrib_val)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
sendAbsVolRspNative(JNIEnv * env,jobject object,jbyteArray address,jint abs_vol,jint label)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
sendRegisterAbsVolRspNative(JNIEnv * env,jobject object,jbyteArray address,jbyte rsp_type,jint abs_vol,jint label)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
getPlaybackStateNative(JNIEnv * env,jobject object,jbyteArray address)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
getNowPlayingListNative(JNIEnv * env,jobject object,jbyteArray address,jbyte start,jbyte items)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
getFolderListNative(JNIEnv * env,jobject object,jbyteArray address,jbyte start,jbyte items)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
getPlayerListNative(JNIEnv * env,jobject object,jbyteArray address,jbyte start,jbyte items)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
changeFolderPathNative(JNIEnv * env,jobject object,jbyteArray address,jbyte direction,jbyteArray uidarr)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
setBrowsedPlayerNative(JNIEnv * env,jobject object,jbyteArray address,jint id)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
setAddressedPlayerNative(JNIEnv * env,jobject object,jbyteArray address,jint id)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
playItemNative(JNIEnv * env,jobject object,jbyteArray address,jbyte scope,jbyteArray uidArr,jint uidCounter)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
register_com_android_bluetooth_avrcp_controller(JNIEnv * env)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