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