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 
    348     if ( (btInf = getBluetoothInterface()) == NULL) {
    349         ALOGE("Bluetooth module is not loaded");
    350         return;
    351     }
    352 
    353     if (sBluetoothHfpClientInterface != NULL) {
    354         ALOGW("Cleaning up Bluetooth HFP Client Interface...");
    355         sBluetoothHfpClientInterface->cleanup();
    356         sBluetoothHfpClientInterface = NULL;
    357     }
    358 
    359     if (mCallbacksObj != NULL) {
    360         ALOGW("Cleaning up Bluetooth HFP Client callback object");
    361         env->DeleteGlobalRef(mCallbacksObj);
    362         mCallbacksObj = NULL;
    363     }
    364 }
    365 
    366 static jboolean connectNative(JNIEnv *env, jobject object, jbyteArray address) {
    367     jbyte *addr;
    368     bt_status_t status;
    369 
    370     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    371 
    372     addr = env->GetByteArrayElements(address, NULL);
    373     if (!addr) {
    374         jniThrowIOException(env, EINVAL);
    375         return JNI_FALSE;
    376     }
    377 
    378     if ((status = sBluetoothHfpClientInterface->connect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
    379         ALOGE("Failed AG connection, status: %d", status);
    380     }
    381     env->ReleaseByteArrayElements(address, addr, 0);
    382     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    383 }
    384 
    385 static jboolean disconnectNative(JNIEnv *env, jobject object, jbyteArray address) {
    386     jbyte *addr;
    387     bt_status_t status;
    388 
    389     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    390 
    391     addr = env->GetByteArrayElements(address, NULL);
    392     if (!addr) {
    393         jniThrowIOException(env, EINVAL);
    394         return JNI_FALSE;
    395     }
    396 
    397     if ( (status = sBluetoothHfpClientInterface->disconnect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
    398         ALOGE("Failed AG disconnection, status: %d", status);
    399     }
    400     env->ReleaseByteArrayElements(address, addr, 0);
    401     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    402 }
    403 
    404 static jboolean connectAudioNative(JNIEnv *env, jobject object, jbyteArray address) {
    405     jbyte *addr;
    406     bt_status_t status;
    407 
    408     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    409 
    410     addr = env->GetByteArrayElements(address, NULL);
    411     if (!addr) {
    412         jniThrowIOException(env, EINVAL);
    413         return JNI_FALSE;
    414     }
    415 
    416     if ( (status = sBluetoothHfpClientInterface->connect_audio((bt_bdaddr_t *)addr)) !=
    417          BT_STATUS_SUCCESS) {
    418         ALOGE("Failed AG audio connection, status: %d", status);
    419     }
    420     env->ReleaseByteArrayElements(address, addr, 0);
    421     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    422 }
    423 
    424 static jboolean disconnectAudioNative(JNIEnv *env, jobject object, jbyteArray address) {
    425     jbyte *addr;
    426     bt_status_t status;
    427 
    428     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    429 
    430     addr = env->GetByteArrayElements(address, NULL);
    431     if (!addr) {
    432         jniThrowIOException(env, EINVAL);
    433         return JNI_FALSE;
    434     }
    435 
    436     if ( (status = sBluetoothHfpClientInterface->disconnect_audio((bt_bdaddr_t *) addr)) !=
    437          BT_STATUS_SUCCESS) {
    438         ALOGE("Failed AG audio disconnection, status: %d", status);
    439     }
    440     env->ReleaseByteArrayElements(address, addr, 0);
    441     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    442 }
    443 
    444 static jboolean startVoiceRecognitionNative(JNIEnv *env, jobject object) {
    445     bt_status_t status;
    446     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    447 
    448     if ( (status = sBluetoothHfpClientInterface->start_voice_recognition()) != BT_STATUS_SUCCESS) {
    449         ALOGE("Failed to start voice recognition, status: %d", status);
    450     }
    451     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    452 }
    453 
    454 static jboolean stopVoiceRecognitionNative(JNIEnv *env, jobject object) {
    455     bt_status_t status;
    456     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    457 
    458     if ( (status = sBluetoothHfpClientInterface->stop_voice_recognition()) != BT_STATUS_SUCCESS) {
    459         ALOGE("Failed to stop voice recognition, status: %d", status);
    460     }
    461     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    462 }
    463 
    464 static jboolean setVolumeNative(JNIEnv *env, jobject object, jint volume_type, jint volume) {
    465     bt_status_t status;
    466     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    467 
    468     if ( (status = sBluetoothHfpClientInterface->volume_control((bthf_client_volume_type_t) volume_type,
    469                                                           volume)) != BT_STATUS_SUCCESS) {
    470         ALOGE("FAILED to control volume, status: %d", status);
    471     }
    472     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    473 }
    474 
    475 static jboolean dialNative(JNIEnv *env, jobject object, jstring number_str) {
    476     bt_status_t status;
    477     const char *number = NULL;
    478     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    479 
    480     if (number_str != NULL) {
    481         number = env->GetStringUTFChars(number_str, NULL);
    482     }
    483 
    484     if ( (status = sBluetoothHfpClientInterface->dial(number)) != BT_STATUS_SUCCESS) {
    485         ALOGE("Failed to dial, status: %d", status);
    486     }
    487     if (number != NULL) {
    488         env->ReleaseStringUTFChars(number_str, number);
    489     }
    490     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    491 }
    492 
    493 static jboolean dialMemoryNative(JNIEnv *env, jobject object, jint location) {
    494     bt_status_t status;
    495 
    496     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    497 
    498     if ( (status = sBluetoothHfpClientInterface->dial_memory((int)location)) != BT_STATUS_SUCCESS) {
    499         ALOGE("Failed to dial from memory, status: %d", status);
    500     }
    501     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    502 }
    503 
    504 static jboolean handleCallActionNative(JNIEnv *env, jobject object, jint action, jint index) {
    505     bt_status_t status;
    506 
    507     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    508 
    509     if ( (status = sBluetoothHfpClientInterface->handle_call_action((bthf_client_call_action_t)action, (int)index)) != BT_STATUS_SUCCESS) {
    510         ALOGE("Failed to enter private mode, status: %d", status);
    511     }
    512     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    513 }
    514 
    515 static jboolean queryCurrentCallsNative(JNIEnv *env, jobject object) {
    516     bt_status_t status;
    517 
    518     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    519 
    520     if ( (status = sBluetoothHfpClientInterface->query_current_calls()) != BT_STATUS_SUCCESS) {
    521         ALOGE("Failed to query current calls, status: %d", status);
    522     }
    523     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    524 }
    525 
    526 static jboolean queryCurrentOperatorNameNative(JNIEnv *env, jobject object) {
    527     bt_status_t status;
    528 
    529     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    530 
    531     if ( (status = sBluetoothHfpClientInterface->query_current_operator_name()) != BT_STATUS_SUCCESS) {
    532         ALOGE("Failed to query current operator name, status: %d", status);
    533     }
    534     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    535 }
    536 
    537 static jboolean retrieveSubscriberInfoNative(JNIEnv *env, jobject object) {
    538     bt_status_t status;
    539 
    540     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    541 
    542     if ( (status = sBluetoothHfpClientInterface->retrieve_subscriber_info()) != BT_STATUS_SUCCESS) {
    543         ALOGE("Failed to retrieve subscriber info, status: %d", status);
    544     }
    545     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    546 }
    547 
    548 static jboolean sendDtmfNative(JNIEnv *env, jobject object, jbyte code) {
    549     bt_status_t status;
    550 
    551     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    552 
    553     if ( (status = sBluetoothHfpClientInterface->send_dtmf((char)code)) != BT_STATUS_SUCCESS) {
    554         ALOGE("Failed to send DTMF, status: %d", status);
    555     }
    556     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    557 }
    558 
    559 static jboolean requestLastVoiceTagNumberNative(JNIEnv *env, jobject object) {
    560     bt_status_t status;
    561 
    562     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    563 
    564     if ( (status = sBluetoothHfpClientInterface->request_last_voice_tag_number()) != BT_STATUS_SUCCESS) {
    565         ALOGE("Failed to request last Voice Tag number, status: %d", status);
    566     }
    567     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    568 }
    569 
    570 static jboolean sendATCmdNative(JNIEnv *env, jobject object, jint cmd,
    571                                 jint val1, jint val2, jstring arg_str) {
    572     bt_status_t status;
    573     const char *arg = NULL;
    574 
    575     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
    576 
    577     if (arg_str != NULL) {
    578         arg = env->GetStringUTFChars(arg_str, NULL);
    579     }
    580 
    581     if ((status = sBluetoothHfpClientInterface->send_at_cmd(cmd,val1,val2,arg)) !=
    582             BT_STATUS_SUCCESS) {
    583         ALOGE("Failed to send cmd, status: %d", status);
    584     }
    585 
    586     if (arg != NULL) {
    587         env->ReleaseStringUTFChars(arg_str, arg);
    588     }
    589     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    590 }
    591 
    592 static JNINativeMethod sMethods[] = {
    593     {"classInitNative", "()V", (void *) classInitNative},
    594     {"initializeNative", "()V", (void *) initializeNative},
    595     {"cleanupNative", "()V", (void *) cleanupNative},
    596     {"connectNative", "([B)Z", (void *) connectNative},
    597     {"disconnectNative", "([B)Z", (void *) disconnectNative},
    598     {"connectAudioNative", "([B)Z", (void *) connectAudioNative},
    599     {"disconnectAudioNative", "([B)Z", (void *) disconnectAudioNative},
    600     {"startVoiceRecognitionNative", "()Z", (void *) startVoiceRecognitionNative},
    601     {"stopVoiceRecognitionNative", "()Z", (void *) stopVoiceRecognitionNative},
    602     {"setVolumeNative", "(II)Z", (void *) setVolumeNative},
    603     {"dialNative", "(Ljava/lang/String;)Z", (void *) dialNative},
    604     {"dialMemoryNative", "(I)Z", (void *) dialMemoryNative},
    605     {"handleCallActionNative", "(II)Z", (void *) handleCallActionNative},
    606     {"queryCurrentCallsNative", "()Z", (void *) queryCurrentCallsNative},
    607     {"queryCurrentOperatorNameNative", "()Z", (void *) queryCurrentOperatorNameNative},
    608     {"retrieveSubscriberInfoNative", "()Z", (void *) retrieveSubscriberInfoNative},
    609     {"sendDtmfNative", "(B)Z", (void *) sendDtmfNative},
    610     {"requestLastVoiceTagNumberNative", "()Z",
    611         (void *) requestLastVoiceTagNumberNative},
    612     {"sendATCmdNative", "(IIILjava/lang/String;)Z", (void *) sendATCmdNative},
    613 };
    614 
    615 int register_com_android_bluetooth_hfpclient(JNIEnv* env)
    616 {
    617     return jniRegisterNativeMethods(env, "com/android/bluetooth/hfpclient/HeadsetClientStateMachine",
    618                                     sMethods, NELEM(sMethods));
    619 }
    620 
    621 } /* namespace android */
    622