• 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(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