Home | History | Annotate | Download | only in jni
      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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
   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 
   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