Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (c) 2014 The Android Open Source Project
      3  * Copyright (C) 2012 The Android Open Source Project
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 #define LOG_TAG "BluetoothHeadsetClientServiceJni"
     19 #define LOG_NDEBUG 0
     20 
     21 #include "android_runtime/AndroidRuntime.h"
     22 #include "com_android_bluetooth.h"
     23 #include "hardware/bt_hf_client.h"
     24 #include "utils/Log.h"
     25 
     26 namespace android {
     27 
     28 static bthf_client_interface_t* sBluetoothHfpClientInterface = NULL;
     29 static jobject mCallbacksObj = NULL;
     30 
     31 static jmethodID method_onConnectionStateChanged;
     32 static jmethodID method_onAudioStateChanged;
     33 static jmethodID method_onVrStateChanged;
     34 static jmethodID method_onNetworkState;
     35 static jmethodID method_onNetworkRoaming;
     36 static jmethodID method_onNetworkSignal;
     37 static jmethodID method_onBatteryLevel;
     38 static jmethodID method_onCurrentOperator;
     39 static jmethodID method_onCall;
     40 static jmethodID method_onCallSetup;
     41 static jmethodID method_onCallHeld;
     42 static jmethodID method_onRespAndHold;
     43 static jmethodID method_onClip;
     44 static jmethodID method_onCallWaiting;
     45 static jmethodID method_onCurrentCalls;
     46 static jmethodID method_onVolumeChange;
     47 static jmethodID method_onCmdResult;
     48 static jmethodID method_onSubscriberInfo;
     49 static jmethodID method_onInBandRing;
     50 static jmethodID method_onLastVoiceTagNumber;
     51 static jmethodID method_onRingIndication;
     52 
     53 static jbyteArray marshall_bda(const bt_bdaddr_t* bd_addr) {
     54   CallbackEnv sCallbackEnv(__func__);
     55   if (!sCallbackEnv.valid()) return NULL;
     56 
     57   jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
     58   if (!addr) {
     59     ALOGE("Fail to new jbyteArray bd addr");
     60     return NULL;
     61   }
     62   sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t),
     63                                    (jbyte*)bd_addr);
     64   return addr;
     65 }
     66 
     67 static void connection_state_cb(const bt_bdaddr_t* bd_addr,
     68                                 bthf_client_connection_state_t state,
     69                                 unsigned int peer_feat,
     70                                 unsigned int chld_feat) {
     71   CallbackEnv sCallbackEnv(__func__);
     72   if (!sCallbackEnv.valid()) return;
     73 
     74   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
     75   if (!addr.get()) return;
     76 
     77   ALOGD("%s: state %d peer_feat %d chld_feat %d", __func__, state, peer_feat, chld_feat);
     78   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged,
     79                                (jint)state, (jint)peer_feat, (jint)chld_feat,
     80                                addr.get());
     81 }
     82 
     83 static void audio_state_cb(const bt_bdaddr_t* bd_addr,
     84                            bthf_client_audio_state_t state) {
     85   CallbackEnv sCallbackEnv(__func__);
     86   if (!sCallbackEnv.valid()) return;
     87 
     88   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
     89   if (!addr.get()) return;
     90 
     91   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioStateChanged,
     92                                (jint)state, addr.get());
     93 }
     94 
     95 static void vr_cmd_cb(const bt_bdaddr_t* bd_addr,
     96                       bthf_client_vr_state_t state) {
     97   CallbackEnv sCallbackEnv(__func__);
     98   if (!sCallbackEnv.valid()) return;
     99   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVrStateChanged,
    100                                (jint)state);
    101 }
    102 
    103 static void network_state_cb(const bt_bdaddr_t* bd_addr,
    104                              bthf_client_network_state_t state) {
    105   CallbackEnv sCallbackEnv(__func__);
    106   if (!sCallbackEnv.valid()) return;
    107 
    108   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
    109   if (!addr.get()) return;
    110 
    111   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNetworkState,
    112                                (jint)state, addr.get());
    113 }
    114 
    115 static void network_roaming_cb(const bt_bdaddr_t* bd_addr,
    116                                bthf_client_service_type_t type) {
    117   CallbackEnv sCallbackEnv(__func__);
    118 
    119   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
    120   if (!addr.get()) return;
    121 
    122   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNetworkRoaming,
    123                                (jint)type, addr.get());
    124 }
    125 
    126 static void network_signal_cb(const bt_bdaddr_t* bd_addr, int signal) {
    127   CallbackEnv sCallbackEnv(__func__);
    128   if (!sCallbackEnv.valid()) return;
    129 
    130   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
    131   if (!addr.get()) return;
    132 
    133   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNetworkSignal,
    134                                (jint)signal, addr.get());
    135 }
    136 
    137 static void battery_level_cb(const bt_bdaddr_t* bd_addr, int level) {
    138   CallbackEnv sCallbackEnv(__func__);
    139   if (!sCallbackEnv.valid()) return;
    140 
    141   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
    142   if (!addr.get()) return;
    143 
    144   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onBatteryLevel,
    145                                (jint)level, addr.get());
    146 }
    147 
    148 static void current_operator_cb(const bt_bdaddr_t* bd_addr, const char* name) {
    149   CallbackEnv sCallbackEnv(__func__);
    150   if (!sCallbackEnv.valid()) return;
    151 
    152   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
    153   if (!addr.get()) return;
    154 
    155   ScopedLocalRef<jstring> js_name(sCallbackEnv.get(),
    156                                   sCallbackEnv->NewStringUTF(name));
    157   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCurrentOperator,
    158                                js_name.get(), addr.get());
    159 }
    160 
    161 static void call_cb(const bt_bdaddr_t* bd_addr, bthf_client_call_t call) {
    162   CallbackEnv sCallbackEnv(__func__);
    163   if (!sCallbackEnv.valid()) return;
    164 
    165   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
    166   if (!addr.get()) return;
    167 
    168   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCall, (jint)call,
    169                                addr.get());
    170 }
    171 
    172 static void callsetup_cb(const bt_bdaddr_t* bd_addr,
    173                          bthf_client_callsetup_t callsetup) {
    174   CallbackEnv sCallbackEnv(__func__);
    175   if (!sCallbackEnv.valid()) return;
    176 
    177   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
    178   if (!addr.get()) return;
    179 
    180   ALOGD("callsetup_cb bdaddr %02x:%02x:%02x:%02x:%02x:%02x",
    181         bd_addr->address[0], bd_addr->address[1], bd_addr->address[2],
    182         bd_addr->address[3], bd_addr->address[4], bd_addr->address[5]);
    183 
    184   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCallSetup,
    185                                (jint)callsetup, addr.get());
    186 }
    187 
    188 static void callheld_cb(const bt_bdaddr_t* bd_addr,
    189                         bthf_client_callheld_t callheld) {
    190   CallbackEnv sCallbackEnv(__func__);
    191   if (!sCallbackEnv.valid()) return;
    192 
    193   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
    194   if (!addr.get()) return;
    195 
    196   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCallHeld, (jint)callheld,
    197                                addr.get());
    198 }
    199 
    200 static void resp_and_hold_cb(const bt_bdaddr_t* bd_addr,
    201                              bthf_client_resp_and_hold_t resp_and_hold) {
    202   CallbackEnv sCallbackEnv(__func__);
    203   if (!sCallbackEnv.valid()) return;
    204 
    205   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
    206   if (!addr.get()) return;
    207 
    208   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onRespAndHold,
    209                                (jint)resp_and_hold, addr.get());
    210 }
    211 
    212 static void clip_cb(const bt_bdaddr_t* bd_addr, const char* number) {
    213   CallbackEnv sCallbackEnv(__func__);
    214   if (!sCallbackEnv.valid()) return;
    215 
    216   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
    217   if (!addr.get()) return;
    218 
    219   ScopedLocalRef<jstring> js_number(sCallbackEnv.get(),
    220                                     sCallbackEnv->NewStringUTF(number));
    221   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onClip, js_number.get(),
    222                                addr.get());
    223 }
    224 
    225 static void call_waiting_cb(const bt_bdaddr_t* bd_addr, const char* number) {
    226   CallbackEnv sCallbackEnv(__func__);
    227   if (!sCallbackEnv.valid()) return;
    228 
    229   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
    230   if (!addr.get()) return;
    231   ScopedLocalRef<jstring> js_number(sCallbackEnv.get(),
    232                                     sCallbackEnv->NewStringUTF(number));
    233   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCallWaiting,
    234                                js_number.get(), addr.get());
    235 }
    236 
    237 static void current_calls_cb(const bt_bdaddr_t* bd_addr, int index,
    238                              bthf_client_call_direction_t dir,
    239                              bthf_client_call_state_t state,
    240                              bthf_client_call_mpty_type_t mpty,
    241                              const char* number) {
    242   CallbackEnv sCallbackEnv(__func__);
    243   if (!sCallbackEnv.valid()) return;
    244 
    245   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
    246   if (!addr.get()) return;
    247   ScopedLocalRef<jstring> js_number(sCallbackEnv.get(),
    248                                     sCallbackEnv->NewStringUTF(number));
    249   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCurrentCalls, index, dir,
    250                                state, mpty, js_number.get(), addr.get());
    251 }
    252 
    253 static void volume_change_cb(const bt_bdaddr_t* bd_addr,
    254                              bthf_client_volume_type_t type, int volume) {
    255   CallbackEnv sCallbackEnv(__func__);
    256   if (!sCallbackEnv.valid()) return;
    257 
    258   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
    259   if (!addr.get()) return;
    260   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVolumeChange, (jint)type,
    261                                (jint)volume, addr.get());
    262 }
    263 
    264 static void cmd_complete_cb(const bt_bdaddr_t* bd_addr,
    265                             bthf_client_cmd_complete_t type, int cme) {
    266   CallbackEnv sCallbackEnv(__func__);
    267   if (!sCallbackEnv.valid()) return;
    268 
    269   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
    270   if (!addr.get()) return;
    271   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCmdResult, (jint)type,
    272                                (jint)cme, addr.get());
    273 }
    274 
    275 static void subscriber_info_cb(const bt_bdaddr_t* bd_addr, const char* name,
    276                                bthf_client_subscriber_service_type_t type) {
    277   CallbackEnv sCallbackEnv(__func__);
    278   if (!sCallbackEnv.valid()) return;
    279 
    280   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
    281   if (!addr.get()) return;
    282   ScopedLocalRef<jstring> js_name(sCallbackEnv.get(),
    283                                   sCallbackEnv->NewStringUTF(name));
    284   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onSubscriberInfo,
    285                                js_name.get(), (jint)type, addr.get());
    286 }
    287 
    288 static void in_band_ring_cb(const bt_bdaddr_t* bd_addr,
    289                             bthf_client_in_band_ring_state_t in_band) {
    290   CallbackEnv sCallbackEnv(__func__);
    291   if (!sCallbackEnv.valid()) return;
    292 
    293   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
    294   if (!addr.get()) return;
    295   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onInBandRing,
    296                                (jint)in_band, addr.get());
    297 }
    298 
    299 static void last_voice_tag_number_cb(const bt_bdaddr_t* bd_addr,
    300                                      const char* number) {
    301   CallbackEnv sCallbackEnv(__func__);
    302   if (!sCallbackEnv.valid()) return;
    303 
    304   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
    305   if (!addr.get()) return;
    306   ScopedLocalRef<jstring> js_number(sCallbackEnv.get(),
    307                                     sCallbackEnv->NewStringUTF(number));
    308   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onLastVoiceTagNumber,
    309                                js_number.get(), addr.get());
    310 }
    311 
    312 static void ring_indication_cb(const bt_bdaddr_t* bd_addr) {
    313   CallbackEnv sCallbackEnv(__func__);
    314   if (!sCallbackEnv.valid()) return;
    315 
    316   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
    317   if (!addr.get()) return;
    318   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onRingIndication,
    319                                addr.get());
    320 }
    321 
    322 static bthf_client_callbacks_t sBluetoothHfpClientCallbacks = {
    323     sizeof(sBluetoothHfpClientCallbacks),
    324     connection_state_cb,
    325     audio_state_cb,
    326     vr_cmd_cb,
    327     network_state_cb,
    328     network_roaming_cb,
    329     network_signal_cb,
    330     battery_level_cb,
    331     current_operator_cb,
    332     call_cb,
    333     callsetup_cb,
    334     callheld_cb,
    335     resp_and_hold_cb,
    336     clip_cb,
    337     call_waiting_cb,
    338     current_calls_cb,
    339     volume_change_cb,
    340     cmd_complete_cb,
    341     subscriber_info_cb,
    342     in_band_ring_cb,
    343     last_voice_tag_number_cb,
    344     ring_indication_cb,
    345 };
    346 
    347 static void classInitNative(JNIEnv* env, jclass clazz) {
    348   method_onConnectionStateChanged =
    349       env->GetMethodID(clazz, "onConnectionStateChanged", "(III[B)V");
    350   method_onAudioStateChanged =
    351       env->GetMethodID(clazz, "onAudioStateChanged", "(I[B)V");
    352   method_onVrStateChanged = env->GetMethodID(clazz, "onVrStateChanged", "(I)V");
    353   method_onNetworkState = env->GetMethodID(clazz, "onNetworkState", "(I[B)V");
    354   method_onNetworkRoaming = env->GetMethodID(clazz, "onNetworkRoaming", "(I[B)V");
    355   method_onNetworkSignal = env->GetMethodID(clazz, "onNetworkSignal", "(I[B)V");
    356   method_onBatteryLevel = env->GetMethodID(clazz, "onBatteryLevel", "(I[B)V");
    357   method_onCurrentOperator =
    358       env->GetMethodID(clazz, "onCurrentOperator", "(Ljava/lang/String;[B)V");
    359   method_onCall = env->GetMethodID(clazz, "onCall", "(I[B)V");
    360   method_onCallSetup = env->GetMethodID(clazz, "onCallSetup", "(I[B)V");
    361   method_onCallHeld = env->GetMethodID(clazz, "onCallHeld", "(I[B)V");
    362   method_onRespAndHold = env->GetMethodID(clazz, "onRespAndHold", "(I[B)V");
    363   method_onClip = env->GetMethodID(clazz, "onClip", "(Ljava/lang/String;[B)V");
    364   method_onCallWaiting =
    365       env->GetMethodID(clazz, "onCallWaiting", "(Ljava/lang/String;[B)V");
    366   method_onCurrentCalls =
    367       env->GetMethodID(clazz, "onCurrentCalls", "(IIIILjava/lang/String;[B)V");
    368   method_onVolumeChange = env->GetMethodID(clazz, "onVolumeChange", "(II[B)V");
    369   method_onCmdResult = env->GetMethodID(clazz, "onCmdResult", "(II[B)V");
    370   method_onSubscriberInfo =
    371       env->GetMethodID(clazz, "onSubscriberInfo", "(Ljava/lang/String;I[B)V");
    372   method_onInBandRing = env->GetMethodID(clazz, "onInBandRing", "(I[B)V");
    373   method_onLastVoiceTagNumber =
    374       env->GetMethodID(clazz, "onLastVoiceTagNumber", "(Ljava/lang/String;[B)V");
    375   method_onRingIndication = env->GetMethodID(clazz, "onRingIndication", "([B)V");
    376 
    377   ALOGI("%s succeeds", __func__);
    378 }
    379 
    380 static void initializeNative(JNIEnv* env, jobject object) {
    381   ALOGD("%s: HfpClient", __func__);
    382   const bt_interface_t* btInf = getBluetoothInterface();
    383   if (btInf == NULL) {
    384     ALOGE("Bluetooth module is not loaded");
    385     return;
    386   }
    387 
    388   if (sBluetoothHfpClientInterface != NULL) {
    389     ALOGW("Cleaning up Bluetooth HFP Client Interface before initializing");
    390     sBluetoothHfpClientInterface->cleanup();
    391     sBluetoothHfpClientInterface = NULL;
    392   }
    393 
    394   if (mCallbacksObj != NULL) {
    395     ALOGW("Cleaning up Bluetooth HFP Client callback object");
    396     env->DeleteGlobalRef(mCallbacksObj);
    397     mCallbacksObj = NULL;
    398   }
    399 
    400   sBluetoothHfpClientInterface =
    401       (bthf_client_interface_t*)btInf->get_profile_interface(
    402           BT_PROFILE_HANDSFREE_CLIENT_ID);
    403   if (sBluetoothHfpClientInterface == NULL) {
    404     ALOGE("Failed to get Bluetooth HFP Client Interface");
    405     return;
    406   }
    407 
    408   bt_status_t status =
    409       sBluetoothHfpClientInterface->init(&sBluetoothHfpClientCallbacks);
    410   if (status != BT_STATUS_SUCCESS) {
    411     ALOGE("Failed to initialize Bluetooth HFP Client, status: %d", status);
    412     sBluetoothHfpClientInterface = NULL;
    413     return;
    414   }
    415 
    416   mCallbacksObj = env->NewGlobalRef(object);
    417 }
    418 
    419 static void cleanupNative(JNIEnv* env, jobject object) {
    420   const bt_interface_t* btInf = getBluetoothInterface();
    421   if (btInf == NULL) {
    422     ALOGE("Bluetooth module is not loaded");
    423     return;
    424   }
    425 
    426   if (sBluetoothHfpClientInterface != NULL) {
    427     ALOGW("Cleaning up Bluetooth HFP Client Interface...");
    428     sBluetoothHfpClientInterface->cleanup();
    429     sBluetoothHfpClientInterface = NULL;
    430   }
    431 
    432   if (mCallbacksObj != NULL) {
    433     ALOGW("Cleaning up Bluetooth HFP Client callback object");
    434     env->DeleteGlobalRef(mCallbacksObj);
    435     mCallbacksObj = NULL;
    436   }
    437 }
    438 
    439 static jboolean connectNative(JNIEnv* env, jobject object, jbyteArray address) {
    440   if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    441 
    442   jbyte* addr = env->GetByteArrayElements(address, NULL);
    443   if (!addr) {
    444     jniThrowIOException(env, EINVAL);
    445     return JNI_FALSE;
    446   }
    447 
    448   bt_status_t status =
    449       sBluetoothHfpClientInterface->connect((bt_bdaddr_t*)addr);
    450   if (status != BT_STATUS_SUCCESS) {
    451     ALOGE("Failed AG connection, status: %d", status);
    452   }
    453   env->ReleaseByteArrayElements(address, addr, 0);
    454   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    455 }
    456 
    457 static jboolean disconnectNative(JNIEnv* env, jobject object,
    458                                  jbyteArray address) {
    459   if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    460 
    461   jbyte* addr = env->GetByteArrayElements(address, NULL);
    462   if (!addr) {
    463     jniThrowIOException(env, EINVAL);
    464     return JNI_FALSE;
    465   }
    466 
    467   bt_status_t status =
    468       sBluetoothHfpClientInterface->disconnect((const bt_bdaddr_t*)addr);
    469   if (status != BT_STATUS_SUCCESS) {
    470     ALOGE("Failed AG disconnection, status: %d", status);
    471   }
    472   env->ReleaseByteArrayElements(address, addr, 0);
    473   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    474 }
    475 
    476 static jboolean connectAudioNative(JNIEnv* env, jobject object,
    477                                    jbyteArray address) {
    478   if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    479 
    480   jbyte* addr = env->GetByteArrayElements(address, NULL);
    481   if (!addr) {
    482     jniThrowIOException(env, EINVAL);
    483     return JNI_FALSE;
    484   }
    485 
    486   bt_status_t status =
    487       sBluetoothHfpClientInterface->connect_audio((const bt_bdaddr_t*)addr);
    488   if (status != BT_STATUS_SUCCESS) {
    489     ALOGE("Failed AG audio connection, status: %d", status);
    490   }
    491   env->ReleaseByteArrayElements(address, addr, 0);
    492   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    493 }
    494 
    495 static jboolean disconnectAudioNative(JNIEnv* env, jobject object,
    496                                       jbyteArray address) {
    497   if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    498 
    499   jbyte* addr = env->GetByteArrayElements(address, NULL);
    500   if (!addr) {
    501     jniThrowIOException(env, EINVAL);
    502     return JNI_FALSE;
    503   }
    504 
    505   bt_status_t status =
    506       sBluetoothHfpClientInterface->disconnect_audio((const bt_bdaddr_t*)addr);
    507   if (status != BT_STATUS_SUCCESS) {
    508     ALOGE("Failed AG audio disconnection, status: %d", status);
    509   }
    510   env->ReleaseByteArrayElements(address, addr, 0);
    511   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    512 }
    513 
    514 static jboolean startVoiceRecognitionNative(JNIEnv* env, jobject object,
    515                                             jbyteArray address) {
    516   if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    517 
    518   jbyte* addr = env->GetByteArrayElements(address, NULL);
    519   if (!addr) {
    520     jniThrowIOException(env, EINVAL);
    521     return JNI_FALSE;
    522   }
    523 
    524   bt_status_t status = sBluetoothHfpClientInterface->start_voice_recognition(
    525       (const bt_bdaddr_t*)addr);
    526   if (status != BT_STATUS_SUCCESS) {
    527     ALOGE("Failed to start voice recognition, status: %d", status);
    528   }
    529   env->ReleaseByteArrayElements(address, addr, 0);
    530   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    531 }
    532 
    533 static jboolean stopVoiceRecognitionNative(JNIEnv* env, jobject object,
    534                                            jbyteArray address) {
    535   if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    536 
    537   jbyte* addr = env->GetByteArrayElements(address, NULL);
    538   if (!addr) {
    539     jniThrowIOException(env, EINVAL);
    540     return JNI_FALSE;
    541   }
    542 
    543   bt_status_t status = sBluetoothHfpClientInterface->stop_voice_recognition(
    544       (const bt_bdaddr_t*)addr);
    545   if (status != BT_STATUS_SUCCESS) {
    546     ALOGE("Failed to stop voice recognition, status: %d", status);
    547   }
    548   env->ReleaseByteArrayElements(address, addr, 0);
    549   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    550 }
    551 
    552 static jboolean setVolumeNative(JNIEnv* env, jobject object, jbyteArray address,
    553                                 jint volume_type, jint volume) {
    554   if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    555 
    556   jbyte* addr = env->GetByteArrayElements(address, NULL);
    557   if (!addr) {
    558     jniThrowIOException(env, EINVAL);
    559     return JNI_FALSE;
    560   }
    561 
    562   bt_status_t status = sBluetoothHfpClientInterface->volume_control(
    563       (const bt_bdaddr_t*)addr, (bthf_client_volume_type_t)volume_type, volume);
    564   if (status != BT_STATUS_SUCCESS) {
    565     ALOGE("FAILED to control volume, status: %d", status);
    566   }
    567   env->ReleaseByteArrayElements(address, addr, 0);
    568   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    569 }
    570 
    571 static jboolean dialNative(JNIEnv* env, jobject object, jbyteArray address,
    572                            jstring number_str) {
    573   if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    574 
    575   jbyte* addr = env->GetByteArrayElements(address, NULL);
    576   if (!addr) {
    577     jniThrowIOException(env, EINVAL);
    578     return JNI_FALSE;
    579   }
    580 
    581   const char* number = NULL;
    582   if (number_str != NULL) {
    583     number = env->GetStringUTFChars(number_str, NULL);
    584   }
    585 
    586   bt_status_t status =
    587       sBluetoothHfpClientInterface->dial((const bt_bdaddr_t*)addr, number);
    588   if (status != BT_STATUS_SUCCESS) {
    589     ALOGE("Failed to dial, status: %d", status);
    590   }
    591   if (number != NULL) {
    592     env->ReleaseStringUTFChars(number_str, number);
    593   }
    594   env->ReleaseByteArrayElements(address, addr, 0);
    595   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    596 }
    597 
    598 static jboolean dialMemoryNative(JNIEnv* env, jobject object,
    599                                  jbyteArray address, jint location) {
    600   if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    601 
    602   jbyte* addr = env->GetByteArrayElements(address, NULL);
    603   if (!addr) {
    604     jniThrowIOException(env, EINVAL);
    605     return JNI_FALSE;
    606   }
    607 
    608   bt_status_t status = sBluetoothHfpClientInterface->dial_memory(
    609       (const bt_bdaddr_t*)addr, (int)location);
    610   if (status != BT_STATUS_SUCCESS) {
    611     ALOGE("Failed to dial from memory, status: %d", status);
    612   }
    613 
    614   env->ReleaseByteArrayElements(address, addr, 0);
    615   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    616 }
    617 
    618 static jboolean handleCallActionNative(JNIEnv* env, jobject object,
    619                                        jbyteArray address, jint action,
    620                                        jint index) {
    621   if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    622 
    623   jbyte* addr = env->GetByteArrayElements(address, NULL);
    624   if (!addr) {
    625     jniThrowIOException(env, EINVAL);
    626     return JNI_FALSE;
    627   }
    628 
    629   bt_status_t status = sBluetoothHfpClientInterface->handle_call_action(
    630       (const bt_bdaddr_t*)addr, (bthf_client_call_action_t)action, (int)index);
    631 
    632   if (status != BT_STATUS_SUCCESS) {
    633     ALOGE("Failed to enter private mode, status: %d", status);
    634   }
    635   env->ReleaseByteArrayElements(address, addr, 0);
    636   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    637 }
    638 
    639 static jboolean queryCurrentCallsNative(JNIEnv* env, jobject object,
    640                                         jbyteArray address) {
    641   if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    642 
    643   jbyte* addr = env->GetByteArrayElements(address, NULL);
    644   if (!addr) {
    645     jniThrowIOException(env, EINVAL);
    646     return JNI_FALSE;
    647   }
    648 
    649   bt_status_t status = sBluetoothHfpClientInterface->query_current_calls(
    650       (const bt_bdaddr_t*)addr);
    651 
    652   if (status != BT_STATUS_SUCCESS) {
    653     ALOGE("Failed to query current calls, status: %d", status);
    654   }
    655   env->ReleaseByteArrayElements(address, addr, 0);
    656   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    657 }
    658 
    659 static jboolean queryCurrentOperatorNameNative(JNIEnv* env, jobject object,
    660                                                jbyteArray address) {
    661   if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    662 
    663   jbyte* addr = env->GetByteArrayElements(address, NULL);
    664   if (!addr) {
    665     jniThrowIOException(env, EINVAL);
    666     return JNI_FALSE;
    667   }
    668 
    669   bt_status_t status =
    670       sBluetoothHfpClientInterface->query_current_operator_name(
    671           (const bt_bdaddr_t*)addr);
    672   if (status != BT_STATUS_SUCCESS) {
    673     ALOGE("Failed to query current operator name, status: %d", status);
    674   }
    675 
    676   env->ReleaseByteArrayElements(address, addr, 0);
    677   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    678 }
    679 
    680 static jboolean retrieveSubscriberInfoNative(JNIEnv* env, jobject object,
    681                                              jbyteArray address) {
    682   if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    683 
    684   jbyte* addr = env->GetByteArrayElements(address, NULL);
    685   if (!addr) {
    686     jniThrowIOException(env, EINVAL);
    687     return JNI_FALSE;
    688   }
    689 
    690   bt_status_t status = sBluetoothHfpClientInterface->retrieve_subscriber_info(
    691       (const bt_bdaddr_t*)addr);
    692   if (status != BT_STATUS_SUCCESS) {
    693     ALOGE("Failed to retrieve subscriber info, status: %d", status);
    694   }
    695 
    696   env->ReleaseByteArrayElements(address, addr, 0);
    697   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    698 }
    699 
    700 static jboolean sendDtmfNative(JNIEnv* env, jobject object, jbyteArray address,
    701                                jbyte code) {
    702   if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    703 
    704   jbyte* addr = env->GetByteArrayElements(address, NULL);
    705   if (!addr) {
    706     jniThrowIOException(env, EINVAL);
    707     return JNI_FALSE;
    708   }
    709 
    710   bt_status_t status = sBluetoothHfpClientInterface->send_dtmf(
    711       (const bt_bdaddr_t*)addr, (char)code);
    712   if (status != BT_STATUS_SUCCESS) {
    713     ALOGE("Failed to send DTMF, status: %d", status);
    714   }
    715 
    716   env->ReleaseByteArrayElements(address, addr, 0);
    717   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    718 }
    719 
    720 static jboolean requestLastVoiceTagNumberNative(JNIEnv* env, jobject object,
    721                                                 jbyteArray address) {
    722   if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    723 
    724   jbyte* addr = env->GetByteArrayElements(address, NULL);
    725   if (!addr) {
    726     jniThrowIOException(env, EINVAL);
    727     return JNI_FALSE;
    728   }
    729 
    730   bt_status_t status =
    731       sBluetoothHfpClientInterface->request_last_voice_tag_number(
    732           (const bt_bdaddr_t*)addr);
    733 
    734   if (status != BT_STATUS_SUCCESS) {
    735     ALOGE("Failed to request last Voice Tag number, status: %d", status);
    736   }
    737 
    738   env->ReleaseByteArrayElements(address, addr, 0);
    739   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    740 }
    741 
    742 static jboolean sendATCmdNative(JNIEnv* env, jobject object, jbyteArray address,
    743                                 jint cmd, jint val1, jint val2,
    744                                 jstring arg_str) {
    745   if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    746 
    747   jbyte* addr = env->GetByteArrayElements(address, NULL);
    748   if (!addr) {
    749     jniThrowIOException(env, EINVAL);
    750     return JNI_FALSE;
    751   }
    752 
    753   const char* arg = NULL;
    754   if (arg_str != NULL) {
    755     arg = env->GetStringUTFChars(arg_str, NULL);
    756   }
    757 
    758   bt_status_t status = sBluetoothHfpClientInterface->send_at_cmd(
    759       (const bt_bdaddr_t*)addr, cmd, val1, val2, arg);
    760 
    761   if (status != BT_STATUS_SUCCESS) {
    762     ALOGE("Failed to send cmd, status: %d", status);
    763   }
    764 
    765   if (arg != NULL) {
    766     env->ReleaseStringUTFChars(arg_str, arg);
    767   }
    768 
    769   env->ReleaseByteArrayElements(address, addr, 0);
    770   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    771 }
    772 
    773 static JNINativeMethod sMethods[] = {
    774     {"classInitNative", "()V", (void*)classInitNative},
    775     {"initializeNative", "()V", (void*)initializeNative},
    776     {"cleanupNative", "()V", (void*)cleanupNative},
    777     {"connectNative", "([B)Z", (void*)connectNative},
    778     {"disconnectNative", "([B)Z", (void*)disconnectNative},
    779     {"connectAudioNative", "([B)Z", (void*)connectAudioNative},
    780     {"disconnectAudioNative", "([B)Z", (void*)disconnectAudioNative},
    781     {"startVoiceRecognitionNative", "([B)Z",
    782      (void*)startVoiceRecognitionNative},
    783     {"stopVoiceRecognitionNative", "([B)Z", (void*)stopVoiceRecognitionNative},
    784     {"setVolumeNative", "([BII)Z", (void*)setVolumeNative},
    785     {"dialNative", "([BLjava/lang/String;)Z", (void*)dialNative},
    786     {"dialMemoryNative", "([BI)Z", (void*)dialMemoryNative},
    787     {"handleCallActionNative", "([BII)Z", (void*)handleCallActionNative},
    788     {"queryCurrentCallsNative", "([B)Z", (void*)queryCurrentCallsNative},
    789     {"queryCurrentOperatorNameNative", "([B)Z",
    790      (void*)queryCurrentOperatorNameNative},
    791     {"retrieveSubscriberInfoNative", "([B)Z",
    792      (void*)retrieveSubscriberInfoNative},
    793     {"sendDtmfNative", "([BB)Z", (void*)sendDtmfNative},
    794     {"requestLastVoiceTagNumberNative", "([B)Z",
    795      (void*)requestLastVoiceTagNumberNative},
    796     {"sendATCmdNative", "([BIIILjava/lang/String;)Z", (void*)sendATCmdNative},
    797 };
    798 
    799 int register_com_android_bluetooth_hfpclient(JNIEnv* env) {
    800   return jniRegisterNativeMethods(
    801       env, "com/android/bluetooth/hfpclient/NativeInterface",
    802       sMethods, NELEM(sMethods));
    803 }
    804 
    805 } /* namespace android */
    806