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