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 "com_android_bluetooth.h"
     22 #include "hardware/bt_hf_client.h"
     23 #include "utils/Log.h"
     24 #include "android_runtime/AndroidRuntime.h"
     25 
     26 #define CHECK_CALLBACK_ENV                                                      \
     27    if (!checkCallbackThread()) {                                                \
     28        ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);\
     29        return;                                                                  \
     30    }
     31 
     32 namespace android {
     33 
     34 static bthf_client_interface_t *sBluetoothHfpClientInterface = NULL;
     35 static jobject mCallbacksObj = NULL;
     36 static JNIEnv *sCallbackEnv = NULL;
     37 
     38 static jmethodID method_onConnectionStateChanged;
     39 static jmethodID method_onAudioStateChanged;
     40 static jmethodID method_onVrStateChanged;
     41 static jmethodID method_onNetworkState;
     42 static jmethodID method_onNetworkRoaming;
     43 static jmethodID method_onNetworkSignal;
     44 static jmethodID method_onBatteryLevel;
     45 static jmethodID method_onCurrentOperator;
     46 static jmethodID method_onCall;
     47 static jmethodID method_onCallSetup;
     48 static jmethodID method_onCallHeld;
     49 static jmethodID method_onRespAndHold;
     50 static jmethodID method_onClip;
     51 static jmethodID method_onCallWaiting;
     52 static jmethodID method_onCurrentCalls;
     53 static jmethodID method_onVolumeChange;
     54 static jmethodID method_onCmdResult;
     55 static jmethodID method_onSubscriberInfo;
     56 static jmethodID method_onInBandRing;
     57 static jmethodID method_onLastVoiceTagNumber;
     58 static jmethodID method_onRingIndication;
     59 
     60 static bool checkCallbackThread() {
     61     // Always fetch the latest callbackEnv from AdapterService.
     62     // Caching this could cause this sCallbackEnv to go out-of-sync
     63     // with the AdapterService's ENV if an ASSOCIATE/DISASSOCIATE event
     64     // is received
     65     sCallbackEnv = getCallbackEnv();
     66     JNIEnv* env = AndroidRuntime::getJNIEnv();
     67     if (sCallbackEnv != env || sCallbackEnv == NULL) return false;
     68     return true;
     69 }
     70 
     71 static void connection_state_cb(bthf_client_connection_state_t state, unsigned int peer_feat, unsigned int chld_feat, bt_bdaddr_t *bd_addr) {
     72     jbyteArray addr;
     73 
     74     CHECK_CALLBACK_ENV
     75 
     76     addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
     77     if (!addr) {
     78         ALOGE("Fail to new jbyteArray bd addr for connection state");
     79         checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
     80         return;
     81     }
     82 
     83     sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
     84     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged, (jint) state, (jint) peer_feat, (jint) chld_feat, addr);
     85     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
     86     sCallbackEnv->DeleteLocalRef(addr);
     87 }
     88 
     89 static void audio_state_cb(bthf_client_audio_state_t state, bt_bdaddr_t *bd_addr) {
     90     jbyteArray addr;
     91 
     92     CHECK_CALLBACK_ENV
     93 
     94     addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
     95     if (!addr) {
     96         ALOGE("Fail to new jbyteArray bd addr for audio state");
     97         checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
     98         return;
     99     }
    100 
    101     sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
    102     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioStateChanged, (jint) state, addr);
    103     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    104     sCallbackEnv->DeleteLocalRef(addr);
    105 }
    106 
    107 static void vr_cmd_cb(bthf_client_vr_state_t state) {
    108     CHECK_CALLBACK_ENV
    109     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVrStateChanged, (jint) state);
    110     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    111 }
    112 
    113 static void network_state_cb (bthf_client_network_state_t state) {
    114     CHECK_CALLBACK_ENV
    115     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNetworkState, (jint) state);
    116     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    117 }
    118 
    119 static void network_roaming_cb (bthf_client_service_type_t type) {
    120     CHECK_CALLBACK_ENV
    121     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNetworkRoaming, (jint) type);
    122     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    123 }
    124 
    125 static void network_signal_cb (int signal) {
    126     CHECK_CALLBACK_ENV
    127     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNetworkSignal, (jint) signal);
    128     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    129 }
    130 
    131 static void battery_level_cb (int level) {
    132     CHECK_CALLBACK_ENV
    133     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onBatteryLevel, (jint) level);
    134     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    135 }
    136 
    137 static void current_operator_cb (const char *name) {
    138     jstring js_name;
    139 
    140     CHECK_CALLBACK_ENV
    141 
    142     js_name = sCallbackEnv->NewStringUTF(name);
    143     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCurrentOperator, js_name);
    144     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    145     sCallbackEnv->DeleteLocalRef(js_name);
    146 }
    147 
    148 static void call_cb (bthf_client_call_t call) {
    149     CHECK_CALLBACK_ENV
    150     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCall, (jint) call);
    151     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    152 }
    153 
    154 static void callsetup_cb (bthf_client_callsetup_t callsetup) {
    155     CHECK_CALLBACK_ENV
    156     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCallSetup, (jint) callsetup);
    157     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    158 }
    159 
    160 static void callheld_cb (bthf_client_callheld_t callheld) {
    161     CHECK_CALLBACK_ENV
    162     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCallHeld, (jint) callheld);
    163     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    164 }
    165 
    166 static void resp_and_hold_cb (bthf_client_resp_and_hold_t resp_and_hold) {
    167     CHECK_CALLBACK_ENV
    168     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onRespAndHold, (jint) resp_and_hold);
    169     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    170 }
    171 
    172 static void clip_cb (const char *number) {
    173     jstring js_number;
    174 
    175     CHECK_CALLBACK_ENV
    176 
    177     js_number = sCallbackEnv->NewStringUTF(number);
    178     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onClip, js_number);
    179     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    180     sCallbackEnv->DeleteLocalRef(js_number);
    181 }
    182 
    183 static void call_waiting_cb (const char *number) {
    184     jstring js_number;
    185 
    186     CHECK_CALLBACK_ENV
    187 
    188     js_number = sCallbackEnv->NewStringUTF(number);
    189     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCallWaiting, js_number);
    190     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    191     sCallbackEnv->DeleteLocalRef(js_number);
    192 }
    193 
    194 static void current_calls_cb (int index, bthf_client_call_direction_t dir,
    195                                             bthf_client_call_state_t state,
    196                                             bthf_client_call_mpty_type_t mpty,
    197                                             const char *number) {
    198     jstring js_number;
    199 
    200     CHECK_CALLBACK_ENV
    201 
    202     js_number = sCallbackEnv->NewStringUTF(number);
    203     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCurrentCalls, index, dir, state, mpty, js_number);
    204     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    205     sCallbackEnv->DeleteLocalRef(js_number);
    206 }
    207 
    208 static void volume_change_cb (bthf_client_volume_type_t type, int volume) {
    209     CHECK_CALLBACK_ENV
    210     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVolumeChange, (jint) type, (jint) volume);
    211     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    212 }
    213 
    214 static void cmd_complete_cb (bthf_client_cmd_complete_t type, int cme) {
    215     CHECK_CALLBACK_ENV
    216     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCmdResult, (jint) type, (jint) cme);
    217     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    218 }
    219 
    220 static void subscriber_info_cb (const char *name, bthf_client_subscriber_service_type_t type) {
    221     jstring js_name;
    222 
    223     CHECK_CALLBACK_ENV
    224 
    225     js_name = sCallbackEnv->NewStringUTF(name);
    226     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onSubscriberInfo, js_name, (jint) type);
    227     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    228     sCallbackEnv->DeleteLocalRef(js_name);
    229 }
    230 
    231 static void in_band_ring_cb (bthf_client_in_band_ring_state_t in_band) {
    232     CHECK_CALLBACK_ENV
    233     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onInBandRing, (jint) in_band);
    234     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    235 }
    236 
    237 static void last_voice_tag_number_cb (const char *number) {
    238     jstring js_number;
    239 
    240     CHECK_CALLBACK_ENV
    241 
    242     js_number = sCallbackEnv->NewStringUTF(number);
    243     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onLastVoiceTagNumber, js_number);
    244     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    245     sCallbackEnv->DeleteLocalRef(js_number);
    246 }
    247 
    248 static void ring_indication_cb () {
    249     CHECK_CALLBACK_ENV
    250     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onRingIndication);
    251     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    252 }
    253 
    254 static bthf_client_callbacks_t sBluetoothHfpClientCallbacks = {
    255     sizeof(sBluetoothHfpClientCallbacks),
    256     connection_state_cb,
    257     audio_state_cb,
    258     vr_cmd_cb,
    259     network_state_cb,
    260     network_roaming_cb,
    261     network_signal_cb,
    262     battery_level_cb,
    263     current_operator_cb,
    264     call_cb,
    265     callsetup_cb,
    266     callheld_cb,
    267     resp_and_hold_cb,
    268     clip_cb,
    269     call_waiting_cb,
    270     current_calls_cb,
    271     volume_change_cb,
    272     cmd_complete_cb,
    273     subscriber_info_cb,
    274     in_band_ring_cb,
    275     last_voice_tag_number_cb,
    276     ring_indication_cb,
    277 };
    278 
    279 static void classInitNative(JNIEnv* env, jclass clazz) {
    280     method_onConnectionStateChanged = env->GetMethodID(clazz, "onConnectionStateChanged", "(III[B)V");
    281     method_onAudioStateChanged = env->GetMethodID(clazz, "onAudioStateChanged", "(I[B)V");
    282     method_onVrStateChanged = env->GetMethodID(clazz, "onVrStateChanged", "(I)V");
    283     method_onNetworkState = env->GetMethodID(clazz, "onNetworkState", "(I)V");
    284     method_onNetworkRoaming = env->GetMethodID(clazz, "onNetworkRoaming", "(I)V");
    285     method_onNetworkSignal = env->GetMethodID(clazz, "onNetworkSignal", "(I)V");
    286     method_onBatteryLevel = env->GetMethodID(clazz, "onBatteryLevel", "(I)V");
    287     method_onCurrentOperator = env->GetMethodID(clazz, "onCurrentOperator", "(Ljava/lang/String;)V");
    288     method_onCall = env->GetMethodID(clazz, "onCall", "(I)V");
    289     method_onCallSetup = env->GetMethodID(clazz, "onCallSetup", "(I)V");
    290     method_onCallHeld = env->GetMethodID(clazz, "onCallHeld", "(I)V");
    291     method_onRespAndHold = env->GetMethodID(clazz, "onRespAndHold", "(I)V");
    292     method_onClip = env->GetMethodID(clazz, "onClip", "(Ljava/lang/String;)V");
    293     method_onCallWaiting = env->GetMethodID(clazz, "onCallWaiting", "(Ljava/lang/String;)V");
    294     method_onCurrentCalls = env->GetMethodID(clazz, "onCurrentCalls", "(IIIILjava/lang/String;)V");
    295     method_onVolumeChange = env->GetMethodID(clazz, "onVolumeChange", "(II)V");
    296     method_onCmdResult = env->GetMethodID(clazz, "onCmdResult", "(II)V");
    297     method_onSubscriberInfo = env->GetMethodID(clazz, "onSubscriberInfo", "(Ljava/lang/String;I)V");
    298     method_onInBandRing = env->GetMethodID(clazz, "onInBandRing", "(I)V");
    299     method_onLastVoiceTagNumber = env->GetMethodID(clazz, "onLastVoiceTagNumber",
    300         "(Ljava/lang/String;)V");
    301     method_onRingIndication = env->GetMethodID(clazz, "onRingIndication","()V");
    302 
    303     ALOGI("%s succeeds", __FUNCTION__);
    304 }
    305 
    306 static void initializeNative(JNIEnv *env, jobject object) {
    307     const bt_interface_t* btInf;
    308     bt_status_t status;
    309 
    310     btInf = getBluetoothInterface();
    311     if (btInf == NULL) {
    312         ALOGE("Bluetooth module is not loaded");
    313         return;
    314     }
    315 
    316     if (sBluetoothHfpClientInterface != NULL) {
    317         ALOGW("Cleaning up Bluetooth HFP Client Interface before initializing");
    318         sBluetoothHfpClientInterface->cleanup();
    319         sBluetoothHfpClientInterface = NULL;
    320     }
    321 
    322     if (mCallbacksObj != NULL) {
    323         ALOGW("Cleaning up Bluetooth HFP Client callback object");
    324         env->DeleteGlobalRef(mCallbacksObj);
    325         mCallbacksObj = NULL;
    326     }
    327 
    328     sBluetoothHfpClientInterface = (bthf_client_interface_t *)
    329             btInf->get_profile_interface(BT_PROFILE_HANDSFREE_CLIENT_ID);
    330     if (sBluetoothHfpClientInterface  == NULL) {
    331         ALOGE("Failed to get Bluetooth HFP Client Interface");
    332         return;
    333     }
    334 
    335     status = sBluetoothHfpClientInterface->init(&sBluetoothHfpClientCallbacks);
    336     if (status != BT_STATUS_SUCCESS) {
    337         ALOGE("Failed to initialize Bluetooth HFP Client, status: %d", status);
    338         sBluetoothHfpClientInterface = NULL;
    339         return;
    340     }
    341 
    342     mCallbacksObj = env->NewGlobalRef(object);
    343 }
    344 
    345 static void cleanupNative(JNIEnv *env, jobject object) {
    346     const bt_interface_t* btInf;
    347     bt_status_t status;
    348 
    349     if ( (btInf = getBluetoothInterface()) == NULL) {
    350         ALOGE("Bluetooth module is not loaded");
    351         return;
    352     }
    353 
    354     if (sBluetoothHfpClientInterface != NULL) {
    355         ALOGW("Cleaning up Bluetooth HFP Client Interface...");
    356         sBluetoothHfpClientInterface->cleanup();
    357         sBluetoothHfpClientInterface = NULL;
    358     }
    359 
    360     if (mCallbacksObj != NULL) {
    361         ALOGW("Cleaning up Bluetooth HFP Client callback object");
    362         env->DeleteGlobalRef(mCallbacksObj);
    363         mCallbacksObj = NULL;
    364     }
    365 }
    366 
    367 static jboolean connectNative(JNIEnv *env, jobject object, jbyteArray address) {
    368     jbyte *addr;
    369     bt_status_t status;
    370 
    371     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    372 
    373     addr = env->GetByteArrayElements(address, NULL);
    374     if (!addr) {
    375         jniThrowIOException(env, EINVAL);
    376         return JNI_FALSE;
    377     }
    378 
    379     if ((status = sBluetoothHfpClientInterface->connect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
    380         ALOGE("Failed AG connection, status: %d", status);
    381     }
    382     env->ReleaseByteArrayElements(address, addr, 0);
    383     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    384 }
    385 
    386 static jboolean disconnectNative(JNIEnv *env, jobject object, jbyteArray address) {
    387     jbyte *addr;
    388     bt_status_t status;
    389 
    390     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    391 
    392     addr = env->GetByteArrayElements(address, NULL);
    393     if (!addr) {
    394         jniThrowIOException(env, EINVAL);
    395         return JNI_FALSE;
    396     }
    397 
    398     if ( (status = sBluetoothHfpClientInterface->disconnect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
    399         ALOGE("Failed AG disconnection, status: %d", status);
    400     }
    401     env->ReleaseByteArrayElements(address, addr, 0);
    402     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    403 }
    404 
    405 static jboolean connectAudioNative(JNIEnv *env, jobject object, jbyteArray address) {
    406     jbyte *addr;
    407     bt_status_t status;
    408 
    409     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    410 
    411     addr = env->GetByteArrayElements(address, NULL);
    412     if (!addr) {
    413         jniThrowIOException(env, EINVAL);
    414         return JNI_FALSE;
    415     }
    416 
    417     if ( (status = sBluetoothHfpClientInterface->connect_audio((bt_bdaddr_t *)addr)) !=
    418          BT_STATUS_SUCCESS) {
    419         ALOGE("Failed AG audio connection, status: %d", status);
    420     }
    421     env->ReleaseByteArrayElements(address, addr, 0);
    422     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    423 }
    424 
    425 static jboolean disconnectAudioNative(JNIEnv *env, jobject object, jbyteArray address) {
    426     jbyte *addr;
    427     bt_status_t status;
    428 
    429     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    430 
    431     addr = env->GetByteArrayElements(address, NULL);
    432     if (!addr) {
    433         jniThrowIOException(env, EINVAL);
    434         return JNI_FALSE;
    435     }
    436 
    437     if ( (status = sBluetoothHfpClientInterface->disconnect_audio((bt_bdaddr_t *) addr)) !=
    438          BT_STATUS_SUCCESS) {
    439         ALOGE("Failed AG audio disconnection, status: %d", status);
    440     }
    441     env->ReleaseByteArrayElements(address, addr, 0);
    442     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    443 }
    444 
    445 static jboolean startVoiceRecognitionNative(JNIEnv *env, jobject object) {
    446     bt_status_t status;
    447     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    448 
    449     if ( (status = sBluetoothHfpClientInterface->start_voice_recognition()) != BT_STATUS_SUCCESS) {
    450         ALOGE("Failed to start voice recognition, status: %d", status);
    451     }
    452     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    453 }
    454 
    455 static jboolean stopVoiceRecognitionNative(JNIEnv *env, jobject object) {
    456     bt_status_t status;
    457     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    458 
    459     if ( (status = sBluetoothHfpClientInterface->stop_voice_recognition()) != BT_STATUS_SUCCESS) {
    460         ALOGE("Failed to stop voice recognition, status: %d", status);
    461     }
    462     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    463 }
    464 
    465 static jboolean setVolumeNative(JNIEnv *env, jobject object, jint volume_type, jint volume) {
    466     bt_status_t status;
    467     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    468 
    469     if ( (status = sBluetoothHfpClientInterface->volume_control((bthf_client_volume_type_t) volume_type,
    470                                                           volume)) != BT_STATUS_SUCCESS) {
    471         ALOGE("FAILED to control volume, status: %d", status);
    472     }
    473     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    474 }
    475 
    476 static jboolean dialNative(JNIEnv *env, jobject object, jstring number_str) {
    477     bt_status_t status;
    478     const char *number;
    479     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    480 
    481     number = env->GetStringUTFChars(number_str, NULL);
    482 
    483     if ( (status = sBluetoothHfpClientInterface->dial(number)) != BT_STATUS_SUCCESS) {
    484         ALOGE("Failed to dial, status: %d", status);
    485     }
    486     env->ReleaseStringUTFChars(number_str, number);
    487     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    488 }
    489 
    490 static jboolean dialMemoryNative(JNIEnv *env, jobject object, jint location) {
    491     bt_status_t status;
    492 
    493     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    494 
    495     if ( (status = sBluetoothHfpClientInterface->dial_memory((int)location)) != BT_STATUS_SUCCESS) {
    496         ALOGE("Failed to dial from memory, status: %d", status);
    497     }
    498     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    499 }
    500 
    501 static jboolean handleCallActionNative(JNIEnv *env, jobject object, jint action, jint index) {
    502     bt_status_t status;
    503 
    504     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    505 
    506     if ( (status = sBluetoothHfpClientInterface->handle_call_action((bthf_client_call_action_t)action, (int)index)) != BT_STATUS_SUCCESS) {
    507         ALOGE("Failed to enter private mode, status: %d", status);
    508     }
    509     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    510 }
    511 
    512 static jboolean queryCurrentCallsNative(JNIEnv *env, jobject object) {
    513     bt_status_t status;
    514 
    515     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    516 
    517     if ( (status = sBluetoothHfpClientInterface->query_current_calls()) != BT_STATUS_SUCCESS) {
    518         ALOGE("Failed to query current calls, status: %d", status);
    519     }
    520     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    521 }
    522 
    523 static jboolean queryCurrentOperatorNameNative(JNIEnv *env, jobject object) {
    524     bt_status_t status;
    525 
    526     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    527 
    528     if ( (status = sBluetoothHfpClientInterface->query_current_operator_name()) != BT_STATUS_SUCCESS) {
    529         ALOGE("Failed to query current operator name, status: %d", status);
    530     }
    531     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    532 }
    533 
    534 static jboolean retrieveSubscriberInfoNative(JNIEnv *env, jobject object) {
    535     bt_status_t status;
    536 
    537     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    538 
    539     if ( (status = sBluetoothHfpClientInterface->retrieve_subscriber_info()) != BT_STATUS_SUCCESS) {
    540         ALOGE("Failed to retrieve subscriber info, status: %d", status);
    541     }
    542     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    543 }
    544 
    545 static jboolean sendDtmfNative(JNIEnv *env, jobject object, jbyte code) {
    546     bt_status_t status;
    547 
    548     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    549 
    550     if ( (status = sBluetoothHfpClientInterface->send_dtmf((char)code)) != BT_STATUS_SUCCESS) {
    551         ALOGE("Failed to send DTMF, status: %d", status);
    552     }
    553     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    554 }
    555 
    556 static jboolean requestLastVoiceTagNumberNative(JNIEnv *env, jobject object) {
    557     bt_status_t status;
    558 
    559     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    560 
    561     if ( (status = sBluetoothHfpClientInterface->request_last_voice_tag_number()) != BT_STATUS_SUCCESS) {
    562         ALOGE("Failed to request last Voice Tag number, status: %d", status);
    563     }
    564     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    565 }
    566 
    567 static jboolean sendATCmdNative(JNIEnv *env, jobject object, jint cmd,
    568                                 jint val1, jint val2, jstring arg_str) {
    569     bt_status_t status;
    570     const char *arg;
    571 
    572     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    573 
    574     arg = env->GetStringUTFChars(arg_str, NULL);
    575 
    576     if ((status = sBluetoothHfpClientInterface->send_at_cmd(cmd,val1,val2,arg)) !=
    577             BT_STATUS_SUCCESS) {
    578         ALOGE("Failed to send cmd, status: %d", status);
    579     }
    580 
    581     env->ReleaseStringUTFChars(arg_str, arg);
    582     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    583 }
    584 
    585 static JNINativeMethod sMethods[] = {
    586     {"classInitNative", "()V", (void *) classInitNative},
    587     {"initializeNative", "()V", (void *) initializeNative},
    588     {"cleanupNative", "()V", (void *) cleanupNative},
    589     {"connectNative", "([B)Z", (void *) connectNative},
    590     {"disconnectNative", "([B)Z", (void *) disconnectNative},
    591     {"connectAudioNative", "([B)Z", (void *) connectAudioNative},
    592     {"disconnectAudioNative", "([B)Z", (void *) disconnectAudioNative},
    593     {"startVoiceRecognitionNative", "()Z", (void *) startVoiceRecognitionNative},
    594     {"stopVoiceRecognitionNative", "()Z", (void *) stopVoiceRecognitionNative},
    595     {"setVolumeNative", "(II)Z", (void *) setVolumeNative},
    596     {"dialNative", "(Ljava/lang/String;)Z", (void *) dialNative},
    597     {"dialMemoryNative", "(I)Z", (void *) dialMemoryNative},
    598     {"handleCallActionNative", "(II)Z", (void *) handleCallActionNative},
    599     {"queryCurrentCallsNative", "()Z", (void *) queryCurrentCallsNative},
    600     {"queryCurrentOperatorNameNative", "()Z", (void *) queryCurrentOperatorNameNative},
    601     {"retrieveSubscriberInfoNative", "()Z", (void *) retrieveSubscriberInfoNative},
    602     {"sendDtmfNative", "(B)Z", (void *) sendDtmfNative},
    603     {"requestLastVoiceTagNumberNative", "()Z",
    604         (void *) requestLastVoiceTagNumberNative},
    605     {"sendATCmdNative", "(IIILjava/lang/String;)Z", (void *) sendATCmdNative},
    606 };
    607 
    608 int register_com_android_bluetooth_hfpclient(JNIEnv* env)
    609 {
    610     return jniRegisterNativeMethods(env, "com/android/bluetooth/hfpclient/HeadsetClientStateMachine",
    611                                     sMethods, NELEM(sMethods));
    612 }
    613 
    614 } /* namespace android */
    615