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