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