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 "BluetoothAvrcpServiceJni"
     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 <inttypes.h>
     27 #include <string.h>
     28 
     29 namespace android {
     30 static jmethodID method_getRcFeatures;
     31 static jmethodID method_getPlayStatus;
     32 static jmethodID method_getElementAttr;
     33 static jmethodID method_registerNotification;
     34 static jmethodID method_volumeChangeCallback;
     35 static jmethodID method_handlePassthroughCmd;
     36 static jmethodID method_getFolderItemsCallback;
     37 static jmethodID method_setAddressedPlayerCallback;
     38 
     39 static jmethodID method_setBrowsedPlayerCallback;
     40 static jmethodID method_changePathCallback;
     41 static jmethodID method_searchCallback;
     42 static jmethodID method_playItemCallback;
     43 static jmethodID method_getItemAttrCallback;
     44 static jmethodID method_addToPlayListCallback;
     45 static jmethodID method_getTotalNumOfItemsCallback;
     46 
     47 static const btrc_interface_t* sBluetoothAvrcpInterface = NULL;
     48 static jobject mCallbacksObj = NULL;
     49 
     50 /* Function declarations */
     51 static bool copy_item_attributes(JNIEnv* env, jobject object,
     52                                  btrc_folder_items_t* pitem,
     53                                  jint* p_attributesIds,
     54                                  jobjectArray attributesArray, int item_idx,
     55                                  int attribCopiedIndex);
     56 
     57 static bool copy_jstring(uint8_t* str, int maxBytes, jstring jstr, JNIEnv* env);
     58 
     59 static void cleanup_items(btrc_folder_items_t* p_items, int numItems);
     60 
     61 static void btavrcp_remote_features_callback(const RawAddress& bd_addr,
     62                                              btrc_remote_features_t features) {
     63   CallbackEnv sCallbackEnv(__func__);
     64   if (!sCallbackEnv.valid()) return;
     65 
     66   if (!mCallbacksObj) {
     67     ALOGE("%s: mCallbacksObj is null", __func__);
     68     return;
     69   }
     70 
     71   ScopedLocalRef<jbyteArray> addr(
     72       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
     73   if (!addr.get()) {
     74     ALOGE("Unable to allocate byte array for bd_addr");
     75     return;
     76   }
     77 
     78   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
     79                                    (jbyte*)bd_addr.address);
     80   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getRcFeatures, addr.get(),
     81                                (jint)features);
     82 }
     83 
     84 /** Callback for play status request */
     85 static void btavrcp_get_play_status_callback(const RawAddress& bd_addr) {
     86   CallbackEnv sCallbackEnv(__func__);
     87   if (!sCallbackEnv.valid()) return;
     88 
     89   if (!mCallbacksObj) {
     90     ALOGE("%s: mCallbacksObj is null", __func__);
     91     return;
     92   }
     93 
     94   ScopedLocalRef<jbyteArray> addr(
     95       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
     96   if (!addr.get()) {
     97     ALOGE("Fail to new jbyteArray bd addr for get_play_status command");
     98     return;
     99   }
    100 
    101   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
    102                                    (jbyte*)bd_addr.address);
    103   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getPlayStatus, addr.get());
    104 }
    105 
    106 static void btavrcp_get_element_attr_callback(uint8_t num_attr,
    107                                               btrc_media_attr_t* p_attrs,
    108                                               const RawAddress& bd_addr) {
    109   CallbackEnv sCallbackEnv(__func__);
    110   if (!sCallbackEnv.valid()) return;
    111 
    112   if (!mCallbacksObj) {
    113     ALOGE("%s: mCallbacksObj is null", __func__);
    114     return;
    115   }
    116 
    117   ScopedLocalRef<jbyteArray> addr(
    118       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
    119   if (!addr.get()) {
    120     ALOGE("Fail to new jbyteArray bd addr for get_element_attr command");
    121     return;
    122   }
    123 
    124   ScopedLocalRef<jintArray> attrs(
    125       sCallbackEnv.get(), (jintArray)sCallbackEnv->NewIntArray(num_attr));
    126   if (!attrs.get()) {
    127     ALOGE("Fail to new jintArray for attrs");
    128     return;
    129   }
    130 
    131   sCallbackEnv->SetIntArrayRegion(attrs.get(), 0, num_attr, (jint*)p_attrs);
    132 
    133   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
    134                                    (jbyte*)bd_addr.address);
    135   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getElementAttr, addr.get(),
    136                                (jbyte)num_attr, attrs.get());
    137 }
    138 
    139 static void btavrcp_register_notification_callback(btrc_event_id_t event_id,
    140                                                    uint32_t param,
    141                                                    const RawAddress& bd_addr) {
    142   CallbackEnv sCallbackEnv(__func__);
    143   if (!sCallbackEnv.valid()) return;
    144 
    145   if (!mCallbacksObj) {
    146     ALOGE("%s: mCallbacksObj is null", __func__);
    147     return;
    148   }
    149 
    150   ScopedLocalRef<jbyteArray> addr(
    151       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
    152   if (!addr.get()) {
    153     ALOGE("Fail to new jbyteArray bd addr for register_notification command");
    154     return;
    155   }
    156 
    157   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
    158                                    (jbyte*)bd_addr.address);
    159   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_registerNotification,
    160                                addr.get(), (jint)event_id, (jint)param);
    161 }
    162 
    163 static void btavrcp_volume_change_callback(uint8_t volume, uint8_t ctype,
    164                                            const RawAddress& bd_addr) {
    165   CallbackEnv sCallbackEnv(__func__);
    166   if (!sCallbackEnv.valid()) return;
    167 
    168   if (!mCallbacksObj) {
    169     ALOGE("%s: mCallbacksObj is null", __func__);
    170     return;
    171   }
    172 
    173   ScopedLocalRef<jbyteArray> addr(
    174       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
    175   if (!addr.get()) {
    176     ALOGE("Fail to new jbyteArray bd addr for volume_change command");
    177     return;
    178   }
    179 
    180   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
    181                                    (jbyte*)bd_addr.address);
    182 
    183   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_volumeChangeCallback,
    184                                addr.get(), (jint)volume, (jint)ctype);
    185 }
    186 
    187 static void btavrcp_passthrough_command_callback(int id, int pressed,
    188                                                  const RawAddress& bd_addr) {
    189   CallbackEnv sCallbackEnv(__func__);
    190   if (!sCallbackEnv.valid()) return;
    191 
    192   if (!mCallbacksObj) {
    193     ALOGE("%s: mCallbacksObj is null", __func__);
    194     return;
    195   }
    196 
    197   ScopedLocalRef<jbyteArray> addr(
    198       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
    199   if (!addr.get()) {
    200     ALOGE("Fail to new jbyteArray bd addr for passthrough_command command");
    201     return;
    202   }
    203   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
    204                                    (jbyte*)bd_addr.address);
    205 
    206   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handlePassthroughCmd,
    207                                addr.get(), (jint)id, (jint)pressed);
    208 }
    209 
    210 static void btavrcp_set_addressed_player_callback(uint16_t player_id,
    211                                                   const RawAddress& bd_addr) {
    212   CallbackEnv sCallbackEnv(__func__);
    213   if (!sCallbackEnv.valid()) return;
    214 
    215   if (!mCallbacksObj) {
    216     ALOGE("%s: mCallbacksObj is null", __func__);
    217     return;
    218   }
    219 
    220   ScopedLocalRef<jbyteArray> addr(
    221       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
    222   if (!addr.get()) {
    223     ALOGE("Fail to new jbyteArray bd addr for set_addressed_player command");
    224     return;
    225   }
    226 
    227   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
    228                                    (jbyte*)bd_addr.address);
    229   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_setAddressedPlayerCallback,
    230                                addr.get(), (jint)player_id);
    231 }
    232 
    233 static void btavrcp_set_browsed_player_callback(uint16_t player_id,
    234                                                 const RawAddress& bd_addr) {
    235   CallbackEnv sCallbackEnv(__func__);
    236   if (!sCallbackEnv.valid()) return;
    237   if (!mCallbacksObj) {
    238     ALOGE("%s: mCallbacksObj is null", __func__);
    239     return;
    240   }
    241 
    242   ScopedLocalRef<jbyteArray> addr(
    243       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
    244   if (!addr.get()) {
    245     ALOGE("Fail to new jbyteArray bd addr for set_browsed_player command");
    246     return;
    247   }
    248   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
    249                                    (jbyte*)bd_addr.address);
    250 
    251   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_setBrowsedPlayerCallback,
    252                                addr.get(), (jint)player_id);
    253 }
    254 
    255 static void btavrcp_get_folder_items_callback(
    256     uint8_t scope, uint32_t start_item, uint32_t end_item, uint8_t num_attr,
    257     uint32_t* p_attr_ids, const RawAddress& bd_addr) {
    258   CallbackEnv sCallbackEnv(__func__);
    259   if (!sCallbackEnv.valid()) return;
    260 
    261   if (!mCallbacksObj) {
    262     ALOGE("%s: mCallbacksObj is null", __func__);
    263     return;
    264   }
    265 
    266   ScopedLocalRef<jbyteArray> addr(
    267       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
    268   if (!addr.get()) {
    269     ALOGE("Fail to new jbyteArray bd addr for get_folder_items command");
    270     return;
    271   }
    272 
    273   uint32_t* puiAttr = (uint32_t*)p_attr_ids;
    274   ScopedLocalRef<jintArray> attr_ids(sCallbackEnv.get(), NULL);
    275   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
    276                                    (jbyte*)bd_addr.address);
    277 
    278   /* check number of attributes requested by remote device */
    279   if ((num_attr != BTRC_NUM_ATTR_ALL) && (num_attr != BTRC_NUM_ATTR_NONE)) {
    280     /* allocate memory for attr_ids only if some attributes passed from below
    281      * layer */
    282     attr_ids.reset((jintArray)sCallbackEnv->NewIntArray(num_attr));
    283     if (!attr_ids.get()) {
    284       ALOGE("Fail to allocate new jintArray for attrs");
    285       return;
    286     }
    287     sCallbackEnv->SetIntArrayRegion(attr_ids.get(), 0, num_attr,
    288                                     (jint*)puiAttr);
    289   }
    290 
    291   sCallbackEnv->CallVoidMethod(
    292       mCallbacksObj, method_getFolderItemsCallback, addr.get(), (jbyte)scope,
    293       (jlong)start_item, (jlong)end_item, (jbyte)num_attr, attr_ids.get());
    294 }
    295 
    296 static void btavrcp_change_path_callback(uint8_t direction, uint8_t* folder_uid,
    297                                          const RawAddress& bd_addr) {
    298   CallbackEnv sCallbackEnv(__func__);
    299   if (!sCallbackEnv.valid()) return;
    300 
    301   if (!mCallbacksObj) {
    302     ALOGE("%s: mCallbacksObj is null", __func__);
    303     return;
    304   }
    305 
    306   ScopedLocalRef<jbyteArray> attrs(sCallbackEnv.get(),
    307                                    sCallbackEnv->NewByteArray(BTRC_UID_SIZE));
    308   if (!attrs.get()) {
    309     ALOGE("Fail to new jintArray for attrs");
    310     return;
    311   }
    312 
    313   ScopedLocalRef<jbyteArray> addr(
    314       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
    315   if (!addr.get()) {
    316     ALOGE("Fail to new jbyteArray bd addr for change_path command");
    317     return;
    318   }
    319 
    320   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
    321                                    (jbyte*)bd_addr.address);
    322   sCallbackEnv->SetByteArrayRegion(
    323       attrs.get(), 0, sizeof(uint8_t) * BTRC_UID_SIZE, (jbyte*)folder_uid);
    324   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_changePathCallback,
    325                                addr.get(), (jbyte)direction, attrs.get());
    326 }
    327 
    328 static void btavrcp_get_item_attr_callback(uint8_t scope, uint8_t* uid,
    329                                            uint16_t uid_counter,
    330                                            uint8_t num_attr,
    331                                            btrc_media_attr_t* p_attrs,
    332                                            const RawAddress& bd_addr) {
    333   CallbackEnv sCallbackEnv(__func__);
    334   if (!sCallbackEnv.valid()) return;
    335 
    336   if (!mCallbacksObj) {
    337     ALOGE("%s: mCallbacksObj is null", __func__);
    338     return;
    339   }
    340 
    341   ScopedLocalRef<jbyteArray> attr_uid(
    342       sCallbackEnv.get(), sCallbackEnv->NewByteArray(BTRC_UID_SIZE));
    343   if (!attr_uid.get()) {
    344     ALOGE("Fail to new jintArray for attr_uid");
    345     return;
    346   }
    347 
    348   ScopedLocalRef<jbyteArray> addr(
    349       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
    350   if (!addr.get()) {
    351     ALOGE("Fail to new jbyteArray bd addr for get_item_attr command");
    352     return;
    353   }
    354 
    355   ScopedLocalRef<jintArray> attrs(
    356       sCallbackEnv.get(), (jintArray)sCallbackEnv->NewIntArray(num_attr));
    357   if (!attrs.get()) {
    358     ALOGE("Fail to new jintArray for attrs");
    359     return;
    360   }
    361 
    362   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
    363                                    (jbyte*)bd_addr.address);
    364   sCallbackEnv->SetIntArrayRegion(attrs.get(), 0, num_attr, (jint*)p_attrs);
    365   sCallbackEnv->SetByteArrayRegion(
    366       attr_uid.get(), 0, sizeof(uint8_t) * BTRC_UID_SIZE, (jbyte*)uid);
    367 
    368   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getItemAttrCallback,
    369                                addr.get(), (jbyte)scope, attr_uid.get(),
    370                                (jint)uid_counter, (jbyte)num_attr, attrs.get());
    371 }
    372 
    373 static void btavrcp_play_item_callback(uint8_t scope, uint16_t uid_counter,
    374                                        uint8_t* uid,
    375                                        const RawAddress& bd_addr) {
    376   CallbackEnv sCallbackEnv(__func__);
    377   if (!sCallbackEnv.valid()) return;
    378   if (!mCallbacksObj) {
    379     ALOGE("%s: mCallbacksObj is null", __func__);
    380     return;
    381   }
    382 
    383   ScopedLocalRef<jbyteArray> attrs(sCallbackEnv.get(),
    384                                    sCallbackEnv->NewByteArray(BTRC_UID_SIZE));
    385   if (!attrs.get()) {
    386     ALOGE("%s: Fail to new jByteArray attrs for play_item command", __func__);
    387     return;
    388   }
    389 
    390   ScopedLocalRef<jbyteArray> addr(
    391       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
    392   if (!addr.get()) {
    393     ALOGE("Fail to new jbyteArray bd addr for play_item command");
    394     return;
    395   }
    396 
    397   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
    398                                    (jbyte*)bd_addr.address);
    399   sCallbackEnv->SetByteArrayRegion(
    400       attrs.get(), 0, sizeof(uint8_t) * BTRC_UID_SIZE, (jbyte*)uid);
    401   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_playItemCallback,
    402                                addr.get(), (jbyte)scope, (jint)uid_counter,
    403                                attrs.get());
    404 }
    405 
    406 static void btavrcp_get_total_num_items_callback(uint8_t scope,
    407                                                  const RawAddress& bd_addr) {
    408   CallbackEnv sCallbackEnv(__func__);
    409   if (!sCallbackEnv.valid()) return;
    410   if (!mCallbacksObj) {
    411     ALOGE("%s: mCallbacksObj is null", __func__);
    412     return;
    413   }
    414 
    415   ScopedLocalRef<jbyteArray> addr(
    416       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
    417   if (!addr.get()) {
    418     ALOGE("Fail to new jbyteArray bd addr for get_total_num_items command");
    419     return;
    420   }
    421 
    422   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
    423                                    (jbyte*)bd_addr.address);
    424   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getTotalNumOfItemsCallback,
    425                                addr.get(), (jbyte)scope);
    426 }
    427 
    428 static void btavrcp_search_callback(uint16_t charset_id, uint16_t str_len,
    429                                     uint8_t* p_str, const RawAddress& bd_addr) {
    430   CallbackEnv sCallbackEnv(__func__);
    431   if (!sCallbackEnv.valid()) return;
    432   if (!mCallbacksObj) {
    433     ALOGE("%s: mCallbacksObj is null", __func__);
    434     return;
    435   }
    436 
    437   ScopedLocalRef<jbyteArray> attrs(sCallbackEnv.get(),
    438                                    sCallbackEnv->NewByteArray(str_len));
    439   if (!attrs.get()) {
    440     ALOGE("Fail to new jintArray for attrs");
    441     return;
    442   }
    443 
    444   ScopedLocalRef<jbyteArray> addr(
    445       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
    446   if (!addr.get()) {
    447     ALOGE("Fail to new jbyteArray bd addr for search command");
    448     return;
    449   }
    450 
    451   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
    452                                    (jbyte*)bd_addr.address);
    453   sCallbackEnv->SetByteArrayRegion(attrs.get(), 0, str_len * sizeof(uint8_t),
    454                                    (jbyte*)p_str);
    455   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_searchCallback, addr.get(),
    456                                (jint)charset_id, attrs.get());
    457 }
    458 
    459 static void btavrcp_add_to_play_list_callback(uint8_t scope, uint8_t* uid,
    460                                               uint16_t uid_counter,
    461                                               const RawAddress& bd_addr) {
    462   CallbackEnv sCallbackEnv(__func__);
    463   if (!sCallbackEnv.valid()) return;
    464   if (!mCallbacksObj) {
    465     ALOGE("%s: mCallbacksObj is null", __func__);
    466     return;
    467   }
    468 
    469   ScopedLocalRef<jbyteArray> addr(
    470       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
    471   if (!addr.get()) {
    472     ALOGE("Fail to new jbyteArray bd addr for add_to_play_list command");
    473     return;
    474   }
    475 
    476   ScopedLocalRef<jbyteArray> attrs(sCallbackEnv.get(),
    477                                    sCallbackEnv->NewByteArray(BTRC_UID_SIZE));
    478   if (!attrs.get()) {
    479     ALOGE("Fail to new jByteArray for attrs");
    480     return;
    481   }
    482 
    483   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
    484                                    (jbyte*)bd_addr.address);
    485   sCallbackEnv->SetByteArrayRegion(
    486       attrs.get(), 0, sizeof(uint8_t) * BTRC_UID_SIZE, (jbyte*)uid);
    487   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_addToPlayListCallback,
    488                                addr.get(), (jbyte)scope, attrs.get(),
    489                                (jint)uid_counter);
    490 }
    491 
    492 static btrc_callbacks_t sBluetoothAvrcpCallbacks = {
    493     sizeof(sBluetoothAvrcpCallbacks),
    494     btavrcp_remote_features_callback,
    495     btavrcp_get_play_status_callback,
    496     NULL,
    497     NULL,
    498     NULL,
    499     NULL,
    500     NULL,
    501     NULL,
    502     btavrcp_get_element_attr_callback,
    503     btavrcp_register_notification_callback,
    504     btavrcp_volume_change_callback,
    505     btavrcp_passthrough_command_callback,
    506     btavrcp_set_addressed_player_callback,
    507     btavrcp_set_browsed_player_callback,
    508     btavrcp_get_folder_items_callback,
    509     btavrcp_change_path_callback,
    510     btavrcp_get_item_attr_callback,
    511     btavrcp_play_item_callback,
    512     btavrcp_get_total_num_items_callback,
    513     btavrcp_search_callback,
    514     btavrcp_add_to_play_list_callback,
    515 };
    516 
    517 static void classInitNative(JNIEnv* env, jclass clazz) {
    518   method_getRcFeatures =
    519       env->GetMethodID(clazz, "getRcFeaturesRequestFromNative", "([BI)V");
    520   method_getPlayStatus =
    521       env->GetMethodID(clazz, "getPlayStatusRequestFromNative", "([B)V");
    522 
    523   method_getElementAttr =
    524       env->GetMethodID(clazz, "getElementAttrRequestFromNative", "([BB[I)V");
    525 
    526   method_registerNotification = env->GetMethodID(
    527       clazz, "registerNotificationRequestFromNative", "([BII)V");
    528 
    529   method_volumeChangeCallback =
    530       env->GetMethodID(clazz, "volumeChangeRequestFromNative", "([BII)V");
    531 
    532   method_handlePassthroughCmd = env->GetMethodID(
    533       clazz, "handlePassthroughCmdRequestFromNative", "([BII)V");
    534 
    535   method_setAddressedPlayerCallback =
    536       env->GetMethodID(clazz, "setAddressedPlayerRequestFromNative", "([BI)V");
    537 
    538   method_setBrowsedPlayerCallback =
    539       env->GetMethodID(clazz, "setBrowsedPlayerRequestFromNative", "([BI)V");
    540 
    541   method_getFolderItemsCallback =
    542       env->GetMethodID(clazz, "getFolderItemsRequestFromNative", "([BBJJB[I)V");
    543 
    544   method_changePathCallback =
    545       env->GetMethodID(clazz, "changePathRequestFromNative", "([BB[B)V");
    546 
    547   method_getItemAttrCallback =
    548       env->GetMethodID(clazz, "getItemAttrRequestFromNative", "([BB[BIB[I)V");
    549 
    550   method_playItemCallback =
    551       env->GetMethodID(clazz, "playItemRequestFromNative", "([BBI[B)V");
    552 
    553   method_getTotalNumOfItemsCallback =
    554       env->GetMethodID(clazz, "getTotalNumOfItemsRequestFromNative", "([BB)V");
    555 
    556   method_searchCallback =
    557       env->GetMethodID(clazz, "searchRequestFromNative", "([BI[B)V");
    558 
    559   method_addToPlayListCallback =
    560       env->GetMethodID(clazz, "addToPlayListRequestFromNative", "([BB[BI)V");
    561 
    562   ALOGI("%s: succeeds", __func__);
    563 }
    564 
    565 static void initNative(JNIEnv* env, jobject object) {
    566   const bt_interface_t* btInf = getBluetoothInterface();
    567   if (btInf == NULL) {
    568     ALOGE("Bluetooth module is not loaded");
    569     return;
    570   }
    571 
    572   if (sBluetoothAvrcpInterface != NULL) {
    573     ALOGW("Cleaning up Avrcp Interface before initializing...");
    574     sBluetoothAvrcpInterface->cleanup();
    575     sBluetoothAvrcpInterface = NULL;
    576   }
    577 
    578   if (mCallbacksObj != NULL) {
    579     ALOGW("Cleaning up Avrcp callback object");
    580     env->DeleteGlobalRef(mCallbacksObj);
    581     mCallbacksObj = NULL;
    582   }
    583 
    584   sBluetoothAvrcpInterface =
    585       (btrc_interface_t*)btInf->get_profile_interface(BT_PROFILE_AV_RC_ID);
    586   if (sBluetoothAvrcpInterface == NULL) {
    587     ALOGE("Failed to get Bluetooth Avrcp Interface");
    588     return;
    589   }
    590 
    591   bt_status_t status =
    592       sBluetoothAvrcpInterface->init(&sBluetoothAvrcpCallbacks);
    593   if (status != BT_STATUS_SUCCESS) {
    594     ALOGE("Failed to initialize Bluetooth Avrcp, status: %d", status);
    595     sBluetoothAvrcpInterface = NULL;
    596     return;
    597   }
    598 
    599   mCallbacksObj = env->NewGlobalRef(object);
    600 }
    601 
    602 static void cleanupNative(JNIEnv* env, jobject object) {
    603   const bt_interface_t* btInf = getBluetoothInterface();
    604   if (btInf == NULL) {
    605     ALOGE("Bluetooth module is not loaded");
    606     return;
    607   }
    608 
    609   if (sBluetoothAvrcpInterface != NULL) {
    610     sBluetoothAvrcpInterface->cleanup();
    611     sBluetoothAvrcpInterface = NULL;
    612   }
    613 
    614   if (mCallbacksObj != NULL) {
    615     env->DeleteGlobalRef(mCallbacksObj);
    616     mCallbacksObj = NULL;
    617   }
    618 }
    619 
    620 static jboolean getPlayStatusRspNative(JNIEnv* env, jobject object,
    621                                        jbyteArray address, jint playStatus,
    622                                        jint songLen, jint songPos) {
    623   if (!sBluetoothAvrcpInterface) {
    624     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
    625     return JNI_FALSE;
    626   }
    627 
    628   jbyte* addr = env->GetByteArrayElements(address, NULL);
    629   if (!addr) {
    630     jniThrowIOException(env, EINVAL);
    631     return JNI_FALSE;
    632   }
    633   RawAddress rawAddress;
    634   rawAddress.FromOctets((uint8_t*)addr);
    635 
    636   bt_status_t status = sBluetoothAvrcpInterface->get_play_status_rsp(
    637       rawAddress, (btrc_play_status_t)playStatus, songLen, songPos);
    638   if (status != BT_STATUS_SUCCESS) {
    639     ALOGE("Failed get_play_status_rsp, status: %d", status);
    640   }
    641   env->ReleaseByteArrayElements(address, addr, 0);
    642   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    643 }
    644 
    645 static jboolean getElementAttrRspNative(JNIEnv* env, jobject object,
    646                                         jbyteArray address, jbyte numAttr,
    647                                         jintArray attrIds,
    648                                         jobjectArray textArray) {
    649   if (!sBluetoothAvrcpInterface) {
    650     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
    651     return JNI_FALSE;
    652   }
    653 
    654   if (numAttr > BTRC_MAX_ELEM_ATTR_SIZE) {
    655     ALOGE("get_element_attr_rsp: number of attributes exceed maximum");
    656     return JNI_FALSE;
    657   }
    658 
    659   jbyte* addr = env->GetByteArrayElements(address, NULL);
    660   if (!addr) {
    661     jniThrowIOException(env, EINVAL);
    662     return JNI_FALSE;
    663   }
    664 
    665   btrc_element_attr_val_t* pAttrs = new btrc_element_attr_val_t[numAttr];
    666   if (!pAttrs) {
    667     ALOGE("get_element_attr_rsp: not have enough memeory");
    668     env->ReleaseByteArrayElements(address, addr, 0);
    669     return JNI_FALSE;
    670   }
    671 
    672   jint* attr = env->GetIntArrayElements(attrIds, NULL);
    673   if (!attr) {
    674     delete[] pAttrs;
    675     jniThrowIOException(env, EINVAL);
    676     env->ReleaseByteArrayElements(address, addr, 0);
    677     return JNI_FALSE;
    678   }
    679 
    680   int attr_cnt;
    681   for (attr_cnt = 0; attr_cnt < numAttr; ++attr_cnt) {
    682     pAttrs[attr_cnt].attr_id = attr[attr_cnt];
    683     ScopedLocalRef<jstring> text(
    684         env, (jstring)env->GetObjectArrayElement(textArray, attr_cnt));
    685 
    686     if (!copy_jstring(pAttrs[attr_cnt].text, BTRC_MAX_ATTR_STR_LEN, text.get(),
    687                       env)) {
    688       break;
    689     }
    690   }
    691 
    692   if (attr_cnt < numAttr) {
    693     delete[] pAttrs;
    694     env->ReleaseIntArrayElements(attrIds, attr, 0);
    695     ALOGE("%s: Failed to copy attributes", __func__);
    696     return JNI_FALSE;
    697   }
    698 
    699   RawAddress rawAddress;
    700   rawAddress.FromOctets((uint8_t*)addr);
    701   bt_status_t status = sBluetoothAvrcpInterface->get_element_attr_rsp(
    702       rawAddress, numAttr, pAttrs);
    703   if (status != BT_STATUS_SUCCESS) {
    704     ALOGE("Failed get_element_attr_rsp, status: %d", status);
    705   }
    706 
    707   delete[] pAttrs;
    708   env->ReleaseIntArrayElements(attrIds, attr, 0);
    709   env->ReleaseByteArrayElements(address, addr, 0);
    710   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    711 }
    712 
    713 static jboolean getItemAttrRspNative(JNIEnv* env, jobject object,
    714                                      jbyteArray address, jint rspStatus,
    715                                      jbyte numAttr, jintArray attrIds,
    716                                      jobjectArray textArray) {
    717   if (!sBluetoothAvrcpInterface) {
    718     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
    719     return JNI_FALSE;
    720   }
    721 
    722   jbyte* addr = env->GetByteArrayElements(address, NULL);
    723   if (!addr) {
    724     jniThrowIOException(env, EINVAL);
    725     return JNI_FALSE;
    726   }
    727 
    728   if (numAttr > BTRC_MAX_ELEM_ATTR_SIZE) {
    729     ALOGE("get_element_attr_rsp: number of attributes exceed maximum");
    730     return JNI_FALSE;
    731   }
    732 
    733   btrc_element_attr_val_t* pAttrs = new btrc_element_attr_val_t[numAttr];
    734   if (!pAttrs) {
    735     ALOGE("%s: not have enough memory", __func__);
    736     env->ReleaseByteArrayElements(address, addr, 0);
    737     return JNI_FALSE;
    738   }
    739 
    740   jint* attr = NULL;
    741   if (attrIds != NULL) {
    742     attr = env->GetIntArrayElements(attrIds, NULL);
    743     if (!attr) {
    744       delete[] pAttrs;
    745       jniThrowIOException(env, EINVAL);
    746       env->ReleaseByteArrayElements(address, addr, 0);
    747       return JNI_FALSE;
    748     }
    749   }
    750 
    751   for (int attr_cnt = 0; attr_cnt < numAttr; ++attr_cnt) {
    752     pAttrs[attr_cnt].attr_id = attr[attr_cnt];
    753     ScopedLocalRef<jstring> text(
    754         env, (jstring)env->GetObjectArrayElement(textArray, attr_cnt));
    755 
    756     if (!copy_jstring(pAttrs[attr_cnt].text, BTRC_MAX_ATTR_STR_LEN, text.get(),
    757                       env)) {
    758       rspStatus = BTRC_STS_INTERNAL_ERR;
    759       ALOGE("%s: Failed to copy attributes", __func__);
    760       break;
    761     }
    762   }
    763   RawAddress rawAddress;
    764   rawAddress.FromOctets((uint8_t*)addr);
    765 
    766   bt_status_t status = sBluetoothAvrcpInterface->get_item_attr_rsp(
    767       rawAddress, (btrc_status_t)rspStatus, numAttr, pAttrs);
    768   if (status != BT_STATUS_SUCCESS)
    769     ALOGE("Failed get_item_attr_rsp, status: %d", status);
    770 
    771   if (pAttrs) delete[] pAttrs;
    772   if (attr) env->ReleaseIntArrayElements(attrIds, attr, 0);
    773   env->ReleaseByteArrayElements(address, addr, 0);
    774 
    775   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    776 }
    777 
    778 static jboolean registerNotificationRspPlayStatusNative(JNIEnv* env,
    779                                                         jobject object,
    780                                                         jint type,
    781                                                         jint playStatus) {
    782   if (!sBluetoothAvrcpInterface) {
    783     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
    784     return JNI_FALSE;
    785   }
    786 
    787   btrc_register_notification_t param;
    788   param.play_status = (btrc_play_status_t)playStatus;
    789 
    790   bt_status_t status = sBluetoothAvrcpInterface->register_notification_rsp(
    791       BTRC_EVT_PLAY_STATUS_CHANGED, (btrc_notification_type_t)type, &param);
    792   if (status != BT_STATUS_SUCCESS) {
    793     ALOGE("Failed register_notification_rsp play status, status: %d", status);
    794   }
    795 
    796   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    797 }
    798 
    799 static jboolean registerNotificationRspTrackChangeNative(JNIEnv* env,
    800                                                          jobject object,
    801                                                          jint type,
    802                                                          jbyteArray track) {
    803   if (!sBluetoothAvrcpInterface) {
    804     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
    805     return JNI_FALSE;
    806   }
    807 
    808   jbyte* trk = env->GetByteArrayElements(track, NULL);
    809   if (!trk) {
    810     jniThrowIOException(env, EINVAL);
    811     return JNI_FALSE;
    812   }
    813 
    814   btrc_register_notification_t param;
    815   uint64_t uid = 0;
    816   for (int uid_idx = 0; uid_idx < BTRC_UID_SIZE; ++uid_idx) {
    817     param.track[uid_idx] = trk[uid_idx];
    818     uid = uid + (trk[uid_idx] << (BTRC_UID_SIZE - 1 - uid_idx));
    819   }
    820 
    821   ALOGV("%s: Sending track change notification: %d -> %" PRIu64, __func__, type,
    822         uid);
    823 
    824   bt_status_t status = sBluetoothAvrcpInterface->register_notification_rsp(
    825       BTRC_EVT_TRACK_CHANGE, (btrc_notification_type_t)type, &param);
    826   if (status != BT_STATUS_SUCCESS) {
    827     ALOGE("Failed register_notification_rsp track change, status: %d", status);
    828   }
    829 
    830   env->ReleaseByteArrayElements(track, trk, 0);
    831   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    832 }
    833 
    834 static jboolean registerNotificationRspPlayPosNative(JNIEnv* env,
    835                                                      jobject object, jint type,
    836                                                      jint playPos) {
    837   if (!sBluetoothAvrcpInterface) {
    838     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
    839     return JNI_FALSE;
    840   }
    841 
    842   btrc_register_notification_t param;
    843   param.song_pos = (uint32_t)playPos;
    844 
    845   bt_status_t status = sBluetoothAvrcpInterface->register_notification_rsp(
    846       BTRC_EVT_PLAY_POS_CHANGED, (btrc_notification_type_t)type, &param);
    847   if (status != BT_STATUS_SUCCESS) {
    848     ALOGE("Failed register_notification_rsp play position, status: %d", status);
    849   }
    850 
    851   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    852 }
    853 
    854 static jboolean registerNotificationRspNowPlayingChangedNative(JNIEnv* env,
    855                                                                jobject object,
    856                                                                jint type) {
    857   if (!sBluetoothAvrcpInterface) {
    858     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
    859     return JNI_FALSE;
    860   }
    861 
    862   btrc_register_notification_t param;
    863   bt_status_t status = sBluetoothAvrcpInterface->register_notification_rsp(
    864       BTRC_EVT_NOW_PLAYING_CONTENT_CHANGED, (btrc_notification_type_t)type,
    865       &param);
    866   if (status != BT_STATUS_SUCCESS) {
    867     ALOGE("Failed register_notification_rsp, nowPlaying Content status: %d",
    868           status);
    869   }
    870   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    871 }
    872 
    873 static jboolean registerNotificationRspUIDsChangedNative(JNIEnv* env,
    874                                                          jobject object,
    875                                                          jint type,
    876                                                          jint uidCounter) {
    877   if (!sBluetoothAvrcpInterface) {
    878     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
    879     return JNI_FALSE;
    880   }
    881 
    882   btrc_register_notification_t param;
    883   param.uids_changed.uid_counter = (uint16_t)uidCounter;
    884 
    885   bt_status_t status = sBluetoothAvrcpInterface->register_notification_rsp(
    886       BTRC_EVT_UIDS_CHANGED, (btrc_notification_type_t)type, &param);
    887   if (status != BT_STATUS_SUCCESS) {
    888     ALOGE("Failed register_notification_rsp, uids changed status: %d", status);
    889   }
    890 
    891   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    892 }
    893 
    894 static jboolean registerNotificationRspAddrPlayerChangedNative(
    895     JNIEnv* env, jobject object, jint type, jint playerId, jint uidCounter) {
    896   if (!sBluetoothAvrcpInterface) {
    897     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
    898     return JNI_FALSE;
    899   }
    900 
    901   btrc_register_notification_t param;
    902   param.addr_player_changed.player_id = (uint16_t)playerId;
    903   param.addr_player_changed.uid_counter = (uint16_t)uidCounter;
    904 
    905   bt_status_t status = sBluetoothAvrcpInterface->register_notification_rsp(
    906       BTRC_EVT_ADDR_PLAYER_CHANGE, (btrc_notification_type_t)type, &param);
    907   if (status != BT_STATUS_SUCCESS) {
    908     ALOGE("Failed register_notification_rsp address player changed status: %d",
    909           status);
    910   }
    911 
    912   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    913 }
    914 
    915 static jboolean registerNotificationRspAvalPlayerChangedNative(JNIEnv* env,
    916                                                                jobject object,
    917                                                                jint type) {
    918   if (!sBluetoothAvrcpInterface) {
    919     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
    920     return JNI_FALSE;
    921   }
    922 
    923   btrc_register_notification_t param;
    924   bt_status_t status = sBluetoothAvrcpInterface->register_notification_rsp(
    925       BTRC_EVT_AVAL_PLAYER_CHANGE, (btrc_notification_type_t)type, &param);
    926   if (status != BT_STATUS_SUCCESS) {
    927     ALOGE(
    928         "Failed register_notification_rsp available player changed status, "
    929         "status: %d",
    930         status);
    931   }
    932 
    933   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    934 }
    935 
    936 static jboolean setVolumeNative(JNIEnv* env, jobject object, jint volume) {
    937   if (!sBluetoothAvrcpInterface) {
    938     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
    939     return JNI_FALSE;
    940   }
    941 
    942   bt_status_t status = sBluetoothAvrcpInterface->set_volume((uint8_t)volume);
    943   if (status != BT_STATUS_SUCCESS) {
    944     ALOGE("Failed set_volume, status: %d", status);
    945   }
    946 
    947   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    948 }
    949 
    950 /* native response for scope as Media player */
    951 static jboolean mediaPlayerListRspNative(
    952     JNIEnv* env, jobject object, jbyteArray address, jint rspStatus,
    953     jint uidCounter, jbyte itemType, jint numItems, jintArray playerIds,
    954     jbyteArray playerTypes, jintArray playerSubtypes,
    955     jbyteArray playStatusValues, jshortArray featureBitmask,
    956     jobjectArray textArray) {
    957   if (!sBluetoothAvrcpInterface) {
    958     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
    959     return JNI_FALSE;
    960   }
    961 
    962   jbyte* addr = env->GetByteArrayElements(address, NULL);
    963   if (!addr) {
    964     jniThrowIOException(env, EINVAL);
    965     return JNI_FALSE;
    966   }
    967 
    968   jbyte *p_playerTypes = NULL, *p_PlayStatusValues = NULL;
    969   jshort* p_FeatBitMaskValues = NULL;
    970   jint *p_playerIds = NULL, *p_playerSubTypes = NULL;
    971   btrc_folder_items_t* p_items = NULL;
    972   if (rspStatus == BTRC_STS_NO_ERROR) {
    973     /* allocate memory */
    974     p_playerIds = env->GetIntArrayElements(playerIds, NULL);
    975     p_playerTypes = env->GetByteArrayElements(playerTypes, NULL);
    976     p_playerSubTypes = env->GetIntArrayElements(playerSubtypes, NULL);
    977     p_PlayStatusValues = env->GetByteArrayElements(playStatusValues, NULL);
    978     p_FeatBitMaskValues = env->GetShortArrayElements(featureBitmask, NULL);
    979     p_items = new btrc_folder_items_t[numItems];
    980     /* deallocate memory and return if allocation failed */
    981     if (!p_playerIds || !p_playerTypes || !p_playerSubTypes ||
    982         !p_PlayStatusValues || !p_FeatBitMaskValues || !p_items) {
    983       if (p_playerIds) env->ReleaseIntArrayElements(playerIds, p_playerIds, 0);
    984       if (p_playerTypes)
    985         env->ReleaseByteArrayElements(playerTypes, p_playerTypes, 0);
    986       if (p_playerSubTypes)
    987         env->ReleaseIntArrayElements(playerSubtypes, p_playerSubTypes, 0);
    988       if (p_PlayStatusValues)
    989         env->ReleaseByteArrayElements(playStatusValues, p_PlayStatusValues, 0);
    990       if (p_FeatBitMaskValues)
    991         env->ReleaseShortArrayElements(featureBitmask, p_FeatBitMaskValues, 0);
    992       if (p_items) delete[] p_items;
    993 
    994       jniThrowIOException(env, EINVAL);
    995       ALOGE("%s: not have enough memory", __func__);
    996       return JNI_FALSE;
    997     }
    998 
    999     p_items->item_type = (uint8_t)itemType;
   1000 
   1001     /* copy list of media players along with other parameters */
   1002     int itemIdx;
   1003     for (itemIdx = 0; itemIdx < numItems; ++itemIdx) {
   1004       p_items[itemIdx].player.player_id = p_playerIds[itemIdx];
   1005       p_items[itemIdx].player.major_type = p_playerTypes[itemIdx];
   1006       p_items[itemIdx].player.sub_type = p_playerSubTypes[itemIdx];
   1007       p_items[itemIdx].player.play_status = p_PlayStatusValues[itemIdx];
   1008       p_items[itemIdx].player.charset_id = BTRC_CHARSET_ID_UTF8;
   1009 
   1010       ScopedLocalRef<jstring> text(
   1011           env, (jstring)env->GetObjectArrayElement(textArray, itemIdx));
   1012       /* copy player name */
   1013       if (!copy_jstring(p_items[itemIdx].player.name, BTRC_MAX_ATTR_STR_LEN,
   1014                         text.get(), env))
   1015         break;
   1016 
   1017       /* Feature bit mask is 128-bit value each */
   1018       for (int InnCnt = 0; InnCnt < 16; InnCnt++) {
   1019         p_items[itemIdx].player.features[InnCnt] =
   1020             (uint8_t)p_FeatBitMaskValues[(itemIdx * 16) + InnCnt];
   1021       }
   1022     }
   1023 
   1024     /* failed to copy list of media players */
   1025     if (itemIdx < numItems) {
   1026       rspStatus = BTRC_STS_INTERNAL_ERR;
   1027       ALOGE("%s: Failed to copy Media player attributes", __func__);
   1028     }
   1029   }
   1030 
   1031   RawAddress* btAddr = (RawAddress*)addr;
   1032   bt_status_t status = sBluetoothAvrcpInterface->get_folder_items_list_rsp(
   1033       *btAddr, (btrc_status_t)rspStatus, uidCounter, numItems, p_items);
   1034   if (status != BT_STATUS_SUCCESS) {
   1035     ALOGE("Failed get_folder_items_list_rsp, status: %d", status);
   1036   }
   1037 
   1038   /* release allocated memory */
   1039   if (p_items) delete[] p_items;
   1040   if (p_playerTypes)
   1041     env->ReleaseByteArrayElements(playerTypes, p_playerTypes, 0);
   1042   if (p_playerSubTypes)
   1043     env->ReleaseIntArrayElements(playerSubtypes, p_playerSubTypes, 0);
   1044   if (p_PlayStatusValues)
   1045     env->ReleaseByteArrayElements(playStatusValues, p_PlayStatusValues, 0);
   1046   if (p_FeatBitMaskValues) {
   1047     env->ReleaseShortArrayElements(featureBitmask, p_FeatBitMaskValues, 0);
   1048   }
   1049   env->ReleaseByteArrayElements(address, addr, 0);
   1050 
   1051   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
   1052 }
   1053 
   1054 static jboolean getFolderItemsRspNative(
   1055     JNIEnv* env, jobject object, jbyteArray address, jint rspStatus,
   1056     jshort uidCounter, jbyte scope, jint numItems, jbyteArray folderType,
   1057     jbyteArray playable, jbyteArray itemType, jbyteArray itemUidArray,
   1058     jobjectArray displayNameArray, jintArray numAttrs, jintArray attributesIds,
   1059     jobjectArray attributesArray) {
   1060   if (!sBluetoothAvrcpInterface) {
   1061     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
   1062     return JNI_FALSE;
   1063   }
   1064 
   1065   jbyte* addr = env->GetByteArrayElements(address, NULL);
   1066   if (!addr) {
   1067     jniThrowIOException(env, EINVAL);
   1068     return JNI_FALSE;
   1069   }
   1070 
   1071   jbyte *p_playable = NULL, *p_item_uid = NULL;
   1072   jbyte* p_item_types = NULL; /* Folder or Media Item */
   1073   jint* p_attributesIds = NULL;
   1074   jbyte* p_folder_types =
   1075       NULL; /* Folder properties like Album/Genre/Artists etc */
   1076   jint* p_num_attrs = NULL;
   1077   btrc_folder_items_t* p_items = NULL;
   1078   /* none of the parameters should be null when no error */
   1079   if (rspStatus == BTRC_STS_NO_ERROR) {
   1080     /* allocate memory to each rsp item */
   1081     if (folderType != NULL)
   1082       p_folder_types = env->GetByteArrayElements(folderType, NULL);
   1083     if (playable != NULL)
   1084       p_playable = env->GetByteArrayElements(playable, NULL);
   1085     if (itemType != NULL)
   1086       p_item_types = env->GetByteArrayElements(itemType, NULL);
   1087     if (NULL != numAttrs)
   1088       p_num_attrs = env->GetIntArrayElements(numAttrs, NULL);
   1089     if (NULL != attributesIds)
   1090       p_attributesIds = env->GetIntArrayElements(attributesIds, NULL);
   1091     if (itemUidArray != NULL)
   1092       p_item_uid = (jbyte*)env->GetByteArrayElements(itemUidArray, NULL);
   1093 
   1094     p_items = new btrc_folder_items_t[numItems];
   1095 
   1096     /* if memory alloc failed, release memory */
   1097     if (p_items && p_folder_types && p_playable && p_item_types && p_item_uid &&
   1098         /* attributes can be null if remote requests 0 attributes */
   1099         ((numAttrs != NULL && p_num_attrs) || (!numAttrs && !p_num_attrs)) &&
   1100         ((attributesIds != NULL && p_attributesIds) ||
   1101          (!attributesIds && !p_attributesIds))) {
   1102       memset(p_items, 0, sizeof(btrc_folder_items_t) * numItems);
   1103       if (scope == BTRC_SCOPE_FILE_SYSTEM || scope == BTRC_SCOPE_SEARCH ||
   1104           scope == BTRC_SCOPE_NOW_PLAYING) {
   1105         int attribCopiedIndex = 0;
   1106         for (int item_idx = 0; item_idx < numItems; item_idx++) {
   1107           if (BTRC_ITEM_FOLDER == p_item_types[item_idx]) {
   1108             btrc_folder_items_t* pitem = &p_items[item_idx];
   1109 
   1110             memcpy(pitem->folder.uid, p_item_uid + item_idx * BTRC_UID_SIZE,
   1111                    BTRC_UID_SIZE);
   1112             pitem->item_type = (uint8_t)BTRC_ITEM_FOLDER;
   1113             pitem->folder.charset_id = BTRC_CHARSET_ID_UTF8;
   1114             pitem->folder.type = p_folder_types[item_idx];
   1115             pitem->folder.playable = p_playable[item_idx];
   1116 
   1117             ScopedLocalRef<jstring> text(
   1118                 env, (jstring)env->GetObjectArrayElement(displayNameArray,
   1119                                                          item_idx));
   1120             if (!copy_jstring(pitem->folder.name, BTRC_MAX_ATTR_STR_LEN,
   1121                               text.get(), env)) {
   1122               rspStatus = BTRC_STS_INTERNAL_ERR;
   1123               ALOGE("%s: failed to copy display name of folder item", __func__);
   1124               break;
   1125             }
   1126           } else if (BTRC_ITEM_MEDIA == p_item_types[item_idx]) {
   1127             btrc_folder_items_t* pitem = &p_items[item_idx];
   1128             memcpy(pitem->media.uid, p_item_uid + item_idx * BTRC_UID_SIZE,
   1129                    BTRC_UID_SIZE);
   1130 
   1131             pitem->item_type = (uint8_t)BTRC_ITEM_MEDIA;
   1132             pitem->media.charset_id = BTRC_CHARSET_ID_UTF8;
   1133             pitem->media.type = BTRC_MEDIA_TYPE_AUDIO;
   1134             pitem->media.num_attrs =
   1135                 (p_num_attrs != NULL) ? p_num_attrs[item_idx] : 0;
   1136 
   1137             ScopedLocalRef<jstring> text(
   1138                 env, (jstring)env->GetObjectArrayElement(displayNameArray,
   1139                                                          item_idx));
   1140             if (!copy_jstring(pitem->media.name, BTRC_MAX_ATTR_STR_LEN,
   1141                               text.get(), env)) {
   1142               rspStatus = BTRC_STS_INTERNAL_ERR;
   1143               ALOGE("%s: failed to copy display name of media item", __func__);
   1144               break;
   1145             }
   1146 
   1147             /* copy item attributes */
   1148             if (!copy_item_attributes(env, object, pitem, p_attributesIds,
   1149                                       attributesArray, item_idx,
   1150                                       attribCopiedIndex)) {
   1151               ALOGE("%s: error in copying attributes of item = %s", __func__,
   1152                     pitem->media.name);
   1153               rspStatus = BTRC_STS_INTERNAL_ERR;
   1154               break;
   1155             }
   1156             attribCopiedIndex += pitem->media.num_attrs;
   1157           }
   1158         }
   1159       }
   1160     } else {
   1161       rspStatus = BTRC_STS_INTERNAL_ERR;
   1162       ALOGE("%s: unable to allocate memory", __func__);
   1163     }
   1164   }
   1165 
   1166   RawAddress* btAddr = (RawAddress*)addr;
   1167   bt_status_t status = sBluetoothAvrcpInterface->get_folder_items_list_rsp(
   1168       *btAddr, (btrc_status_t)rspStatus, uidCounter, numItems, p_items);
   1169   if (status != BT_STATUS_SUCCESS)
   1170     ALOGE("Failed get_folder_items_list_rsp, status: %d", status);
   1171 
   1172   /* Release allocated memory for all attributes in each media item */
   1173   if (p_items) cleanup_items(p_items, numItems);
   1174 
   1175   /* Release allocated memory  */
   1176   if (p_folder_types)
   1177     env->ReleaseByteArrayElements(folderType, p_folder_types, 0);
   1178   if (p_playable) env->ReleaseByteArrayElements(playable, p_playable, 0);
   1179   if (p_item_types) env->ReleaseByteArrayElements(itemType, p_item_types, 0);
   1180   if (p_num_attrs) env->ReleaseIntArrayElements(numAttrs, p_num_attrs, 0);
   1181   if (p_attributesIds)
   1182     env->ReleaseIntArrayElements(attributesIds, p_attributesIds, 0);
   1183   if (p_item_uid) env->ReleaseByteArrayElements(itemUidArray, p_item_uid, 0);
   1184   if (p_items) delete[] p_items;
   1185   env->ReleaseByteArrayElements(address, addr, 0);
   1186 
   1187   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
   1188 }
   1189 
   1190 static jboolean setAddressedPlayerRspNative(JNIEnv* env, jobject object,
   1191                                             jbyteArray address,
   1192                                             jint rspStatus) {
   1193   if (!sBluetoothAvrcpInterface) {
   1194     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
   1195     return JNI_FALSE;
   1196   }
   1197 
   1198   jbyte* addr = env->GetByteArrayElements(address, NULL);
   1199   if (!addr) {
   1200     jniThrowIOException(env, EINVAL);
   1201     return JNI_FALSE;
   1202   }
   1203 
   1204   RawAddress* btAddr = (RawAddress*)addr;
   1205   bt_status_t status = sBluetoothAvrcpInterface->set_addressed_player_rsp(
   1206       *btAddr, (btrc_status_t)rspStatus);
   1207   if (status != BT_STATUS_SUCCESS) {
   1208     ALOGE("Failed set_addressed_player_rsp, status: %d", status);
   1209   }
   1210   env->ReleaseByteArrayElements(address, addr, 0);
   1211 
   1212   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
   1213 }
   1214 
   1215 static jboolean setBrowsedPlayerRspNative(JNIEnv* env, jobject object,
   1216                                           jbyteArray address, jint rspStatus,
   1217                                           jbyte depth, jint numItems,
   1218                                           jobjectArray textArray) {
   1219   if (!sBluetoothAvrcpInterface) {
   1220     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
   1221     return JNI_FALSE;
   1222   }
   1223 
   1224   jbyte* addr = env->GetByteArrayElements(address, NULL);
   1225   if (!addr) {
   1226     jniThrowIOException(env, EINVAL);
   1227     return JNI_FALSE;
   1228   }
   1229 
   1230   btrc_br_folder_name_t* p_folders = NULL;
   1231   if (rspStatus == BTRC_STS_NO_ERROR) {
   1232     if (depth > 0) {
   1233       p_folders = new btrc_br_folder_name_t[depth];
   1234     }
   1235 
   1236     for (int folder_idx = 0; folder_idx < depth; folder_idx++) {
   1237       /* copy folder names */
   1238       ScopedLocalRef<jstring> text(
   1239           env, (jstring)env->GetObjectArrayElement(textArray, folder_idx));
   1240 
   1241       if (!copy_jstring(p_folders[folder_idx].p_str, BTRC_MAX_ATTR_STR_LEN,
   1242                         text.get(), env)) {
   1243         rspStatus = BTRC_STS_INTERNAL_ERR;
   1244         delete[] p_folders;
   1245         env->ReleaseByteArrayElements(address, addr, 0);
   1246         ALOGE("%s: Failed to copy folder name", __func__);
   1247         return JNI_FALSE;
   1248       }
   1249 
   1250       p_folders[folder_idx].str_len =
   1251           strlen((char*)p_folders[folder_idx].p_str);
   1252     }
   1253   }
   1254 
   1255   uint8_t folder_depth =
   1256       depth; /* folder_depth is 0 if current folder is root */
   1257   uint16_t charset_id = BTRC_CHARSET_ID_UTF8;
   1258   RawAddress* btAddr = (RawAddress*)addr;
   1259   bt_status_t status = sBluetoothAvrcpInterface->set_browsed_player_rsp(
   1260       *btAddr, (btrc_status_t)rspStatus, numItems, charset_id, folder_depth,
   1261       p_folders);
   1262   if (status != BT_STATUS_SUCCESS) {
   1263     ALOGE("%s: Failed set_browsed_player_rsp, status: %d", __func__, status);
   1264   }
   1265 
   1266   if (depth > 0) {
   1267     delete[] p_folders;
   1268   }
   1269 
   1270   env->ReleaseByteArrayElements(address, addr, 0);
   1271   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
   1272 }
   1273 
   1274 static jboolean changePathRspNative(JNIEnv* env, jobject object,
   1275                                     jbyteArray address, jint rspStatus,
   1276                                     jint numItems) {
   1277   if (!sBluetoothAvrcpInterface) {
   1278     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
   1279     return JNI_FALSE;
   1280   }
   1281 
   1282   jbyte* addr = env->GetByteArrayElements(address, NULL);
   1283   if (!addr) {
   1284     jniThrowIOException(env, EINVAL);
   1285     return JNI_FALSE;
   1286   }
   1287 
   1288   uint32_t nItems = (uint32_t)numItems;
   1289   RawAddress* btAddr = (RawAddress*)addr;
   1290   bt_status_t status = sBluetoothAvrcpInterface->change_path_rsp(
   1291       *btAddr, (btrc_status_t)rspStatus, (uint32_t)nItems);
   1292   if (status != BT_STATUS_SUCCESS) {
   1293     ALOGE("Failed change_path_rsp, status: %d", status);
   1294   }
   1295   env->ReleaseByteArrayElements(address, addr, 0);
   1296 
   1297   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
   1298 }
   1299 
   1300 static jboolean searchRspNative(JNIEnv* env, jobject object, jbyteArray address,
   1301                                 jint rspStatus, jint uidCounter,
   1302                                 jint numItems) {
   1303   if (!sBluetoothAvrcpInterface) {
   1304     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
   1305     return JNI_FALSE;
   1306   }
   1307 
   1308   jbyte* addr = env->GetByteArrayElements(address, NULL);
   1309   if (!addr) {
   1310     jniThrowIOException(env, EINVAL);
   1311     return JNI_FALSE;
   1312   }
   1313 
   1314   uint32_t nItems = (uint32_t)numItems;
   1315   RawAddress* btAddr = (RawAddress*)addr;
   1316   bt_status_t status = sBluetoothAvrcpInterface->search_rsp(
   1317       *btAddr, (btrc_status_t)rspStatus, (uint32_t)uidCounter,
   1318       (uint32_t)nItems);
   1319   if (status != BT_STATUS_SUCCESS) {
   1320     ALOGE("Failed search_rsp, status: %d", status);
   1321   }
   1322 
   1323   env->ReleaseByteArrayElements(address, addr, 0);
   1324 
   1325   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
   1326 }
   1327 
   1328 static jboolean playItemRspNative(JNIEnv* env, jobject object,
   1329                                   jbyteArray address, jint rspStatus) {
   1330   if (!sBluetoothAvrcpInterface) {
   1331     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
   1332     return JNI_FALSE;
   1333   }
   1334 
   1335   jbyte* addr = env->GetByteArrayElements(address, NULL);
   1336   if (!addr) {
   1337     jniThrowIOException(env, EINVAL);
   1338     return JNI_FALSE;
   1339   }
   1340 
   1341   RawAddress* btAddr = (RawAddress*)addr;
   1342   bt_status_t status = sBluetoothAvrcpInterface->play_item_rsp(
   1343       *btAddr, (btrc_status_t)rspStatus);
   1344   if (status != BT_STATUS_SUCCESS) {
   1345     ALOGE("Failed play_item_rsp, status: %d", status);
   1346   }
   1347   env->ReleaseByteArrayElements(address, addr, 0);
   1348 
   1349   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
   1350 }
   1351 
   1352 static jboolean getTotalNumOfItemsRspNative(JNIEnv* env, jobject object,
   1353                                             jbyteArray address, jint rspStatus,
   1354                                             jint uidCounter, jint numItems) {
   1355   if (!sBluetoothAvrcpInterface) {
   1356     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
   1357     return JNI_FALSE;
   1358   }
   1359 
   1360   jbyte* addr = env->GetByteArrayElements(address, NULL);
   1361   if (!addr) {
   1362     jniThrowIOException(env, EINVAL);
   1363     return JNI_FALSE;
   1364   }
   1365 
   1366   uint32_t nItems = (uint32_t)numItems;
   1367   RawAddress* btAddr = (RawAddress*)addr;
   1368   bt_status_t status = sBluetoothAvrcpInterface->get_total_num_of_items_rsp(
   1369       *btAddr, (btrc_status_t)rspStatus, (uint32_t)uidCounter,
   1370       (uint32_t)nItems);
   1371   if (status != BT_STATUS_SUCCESS) {
   1372     ALOGE("Failed get_total_num_of_items_rsp, status: %d", status);
   1373   }
   1374   env->ReleaseByteArrayElements(address, addr, 0);
   1375 
   1376   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
   1377 }
   1378 
   1379 static jboolean addToNowPlayingRspNative(JNIEnv* env, jobject object,
   1380                                          jbyteArray address, jint rspStatus) {
   1381   if (!sBluetoothAvrcpInterface) {
   1382     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
   1383     return JNI_FALSE;
   1384   }
   1385 
   1386   jbyte* addr = env->GetByteArrayElements(address, NULL);
   1387   if (!addr) {
   1388     jniThrowIOException(env, EINVAL);
   1389     return JNI_FALSE;
   1390   }
   1391 
   1392   RawAddress* btAddr = (RawAddress*)addr;
   1393   bt_status_t status = sBluetoothAvrcpInterface->add_to_now_playing_rsp(
   1394       *btAddr, (btrc_status_t)rspStatus);
   1395   if (status != BT_STATUS_SUCCESS) {
   1396     ALOGE("Failed add_to_now_playing_rsp, status: %d", status);
   1397   }
   1398   env->ReleaseByteArrayElements(address, addr, 0);
   1399 
   1400   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
   1401 }
   1402 
   1403 static JNINativeMethod sMethods[] = {
   1404     {"classInitNative", "()V", (void*)classInitNative},
   1405     {"initNative", "()V", (void*)initNative},
   1406     {"cleanupNative", "()V", (void*)cleanupNative},
   1407     {"getPlayStatusRspNative", "([BIII)Z", (void*)getPlayStatusRspNative},
   1408     {"getElementAttrRspNative", "([BB[I[Ljava/lang/String;)Z",
   1409      (void*)getElementAttrRspNative},
   1410     {"registerNotificationRspPlayStatusNative", "(II)Z",
   1411      (void*)registerNotificationRspPlayStatusNative},
   1412     {"registerNotificationRspTrackChangeNative", "(I[B)Z",
   1413      (void*)registerNotificationRspTrackChangeNative},
   1414     {"registerNotificationRspPlayPosNative", "(II)Z",
   1415      (void*)registerNotificationRspPlayPosNative},
   1416     {"setVolumeNative", "(I)Z", (void*)setVolumeNative},
   1417 
   1418     {"setAddressedPlayerRspNative", "([BI)Z",
   1419      (void*)setAddressedPlayerRspNative},
   1420 
   1421     {"setBrowsedPlayerRspNative", "([BIBI[Ljava/lang/String;)Z",
   1422      (void*)setBrowsedPlayerRspNative},
   1423 
   1424     {"mediaPlayerListRspNative", "([BIIBI[I[B[I[B[S[Ljava/lang/String;)Z",
   1425      (void*)mediaPlayerListRspNative},
   1426 
   1427     {"getFolderItemsRspNative",
   1428      "([BISBI[B[B[B[B[Ljava/lang/String;[I[I[Ljava/lang/String;)Z",
   1429      (void*)getFolderItemsRspNative},
   1430 
   1431     {"changePathRspNative", "([BII)Z", (void*)changePathRspNative},
   1432 
   1433     {"getItemAttrRspNative", "([BIB[I[Ljava/lang/String;)Z",
   1434      (void*)getItemAttrRspNative},
   1435 
   1436     {"playItemRspNative", "([BI)Z", (void*)playItemRspNative},
   1437 
   1438     {"getTotalNumOfItemsRspNative", "([BIII)Z",
   1439      (void*)getTotalNumOfItemsRspNative},
   1440 
   1441     {"searchRspNative", "([BIII)Z", (void*)searchRspNative},
   1442 
   1443     {"addToNowPlayingRspNative", "([BI)Z", (void*)addToNowPlayingRspNative},
   1444 
   1445     {"registerNotificationRspAddrPlayerChangedNative", "(III)Z",
   1446      (void*)registerNotificationRspAddrPlayerChangedNative},
   1447 
   1448     {"registerNotificationRspAvalPlayerChangedNative", "(I)Z",
   1449      (void*)registerNotificationRspAvalPlayerChangedNative},
   1450 
   1451     {"registerNotificationRspUIDsChangedNative", "(II)Z",
   1452      (void*)registerNotificationRspUIDsChangedNative},
   1453 
   1454     {"registerNotificationRspNowPlayingChangedNative", "(I)Z",
   1455      (void*)registerNotificationRspNowPlayingChangedNative}};
   1456 
   1457 int register_com_android_bluetooth_avrcp(JNIEnv* env) {
   1458   return jniRegisterNativeMethods(env, "com/android/bluetooth/avrcp/Avrcp",
   1459                                   sMethods, NELEM(sMethods));
   1460 }
   1461 
   1462 /* Helper function to copy attributes of item.
   1463  * Assumes that all items in response have same number of attributes
   1464  *
   1465  * returns true on succes, false otherwise.
   1466 */
   1467 static bool copy_item_attributes(JNIEnv* env, jobject object,
   1468                                  btrc_folder_items_t* pitem,
   1469                                  jint* p_attributesIds,
   1470                                  jobjectArray attributesArray, int item_idx,
   1471                                  int attribCopiedIndex) {
   1472   bool success = true;
   1473 
   1474   /* copy attributes of the item */
   1475   if (0 < pitem->media.num_attrs) {
   1476     int num_attrs = pitem->media.num_attrs;
   1477     ALOGI("%s num_attr = %d", __func__, num_attrs);
   1478     pitem->media.p_attrs = new btrc_element_attr_val_t[num_attrs];
   1479     if (!pitem->media.p_attrs) {
   1480       return false;
   1481     }
   1482 
   1483     for (int tempAtrCount = 0; tempAtrCount < pitem->media.num_attrs;
   1484          ++tempAtrCount) {
   1485       pitem->media.p_attrs[tempAtrCount].attr_id =
   1486           p_attributesIds[attribCopiedIndex + tempAtrCount];
   1487 
   1488       ScopedLocalRef<jstring> text(
   1489           env, (jstring)env->GetObjectArrayElement(
   1490                    attributesArray, attribCopiedIndex + tempAtrCount));
   1491 
   1492       if (!copy_jstring(pitem->media.p_attrs[tempAtrCount].text,
   1493                         BTRC_MAX_ATTR_STR_LEN, text.get(), env)) {
   1494         success = false;
   1495         ALOGE("%s: failed to copy attributes", __func__);
   1496         break;
   1497       }
   1498     }
   1499   }
   1500   return success;
   1501 }
   1502 
   1503 /* Helper function to copy String data from java to native
   1504  *
   1505  * returns true on succes, false otherwise
   1506  */
   1507 static bool copy_jstring(uint8_t* str, int maxBytes, jstring jstr,
   1508                          JNIEnv* env) {
   1509   if (str == NULL || jstr == NULL || env == NULL) return false;
   1510 
   1511   memset(str, 0, maxBytes);
   1512   const char* p_str = env->GetStringUTFChars(jstr, NULL);
   1513   size_t len = strnlen(p_str, maxBytes - 1);
   1514   memcpy(str, p_str, len);
   1515 
   1516   env->ReleaseStringUTFChars(jstr, p_str);
   1517   return true;
   1518 }
   1519 
   1520 /* Helper function to cleanup items */
   1521 static void cleanup_items(btrc_folder_items_t* p_items, int numItems) {
   1522   for (int item_idx = 0; item_idx < numItems; item_idx++) {
   1523     /* release memory for attributes in case item is media item */
   1524     if ((BTRC_ITEM_MEDIA == p_items[item_idx].item_type) &&
   1525         p_items[item_idx].media.p_attrs != NULL)
   1526       delete[] p_items[item_idx].media.p_attrs;
   1527   }
   1528 }
   1529 }
   1530