• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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