Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "BluetoothHeadsetServiceJni"
     18 
     19 #define LOG_NDEBUG 0
     20 
     21 #define CHECK_CALLBACK_ENV                                                      \
     22    if (!checkCallbackThread()) {                                                \
     23        ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);\
     24        return;                                                                  \
     25    }
     26 
     27 #include "com_android_bluetooth.h"
     28 #include "hardware/bt_hf.h"
     29 #include "utils/Log.h"
     30 #include "android_runtime/AndroidRuntime.h"
     31 
     32 #include <string.h>
     33 
     34 namespace android {
     35 
     36 static jmethodID method_onConnectionStateChanged;
     37 static jmethodID method_onAudioStateChanged;
     38 static jmethodID method_onVrStateChanged;
     39 static jmethodID method_onAnswerCall;
     40 static jmethodID method_onHangupCall;
     41 static jmethodID method_onVolumeChanged;
     42 static jmethodID method_onDialCall;
     43 static jmethodID method_onSendDtmf;
     44 static jmethodID method_onNoiceReductionEnable;
     45 static jmethodID method_onAtChld;
     46 static jmethodID method_onAtCnum;
     47 static jmethodID method_onAtCind;
     48 static jmethodID method_onAtCops;
     49 static jmethodID method_onAtClcc;
     50 static jmethodID method_onUnknownAt;
     51 static jmethodID method_onKeyPressed;
     52 
     53 static const bthf_interface_t *sBluetoothHfpInterface = NULL;
     54 static jobject mCallbacksObj = NULL;
     55 static JNIEnv *sCallbackEnv = NULL;
     56 
     57 static bool checkCallbackThread() {
     58     // Always fetch the latest callbackEnv from AdapterService.
     59     // Caching this could cause this sCallbackEnv to go out-of-sync
     60     // with the AdapterService's ENV if an ASSOCIATE/DISASSOCIATE event
     61     // is received
     62     //if (sCallbackEnv == NULL) {
     63     sCallbackEnv = getCallbackEnv();
     64     //}
     65     JNIEnv* env = AndroidRuntime::getJNIEnv();
     66     if (sCallbackEnv != env || sCallbackEnv == NULL) return false;
     67     return true;
     68 }
     69 
     70 static void connection_state_callback(bthf_connection_state_t state, bt_bdaddr_t* bd_addr) {
     71     jbyteArray addr;
     72 
     73     ALOGI("%s", __FUNCTION__);
     74 
     75     CHECK_CALLBACK_ENV
     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,
     85                                  (jint) state, addr);
     86     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
     87     sCallbackEnv->DeleteLocalRef(addr);
     88 }
     89 
     90 static void audio_state_callback(bthf_audio_state_t state, bt_bdaddr_t* bd_addr) {
     91     jbyteArray addr;
     92 
     93     CHECK_CALLBACK_ENV
     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 voice_recognition_callback(bthf_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 answer_call_callback() {
    114     CHECK_CALLBACK_ENV
    115     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAnswerCall);
    116     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    117 }
    118 
    119 static void hangup_call_callback() {
    120     CHECK_CALLBACK_ENV
    121     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onHangupCall);
    122     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    123 }
    124 
    125 static void volume_control_callback(bthf_volume_type_t type, int volume) {
    126     CHECK_CALLBACK_ENV
    127     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVolumeChanged, (jint) type, (jint) volume);
    128     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    129 }
    130 
    131 static void dial_call_callback(char *number) {
    132     CHECK_CALLBACK_ENV
    133     jstring js_number = sCallbackEnv->NewStringUTF(number);
    134     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onDialCall,
    135                                  js_number);
    136     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    137     sCallbackEnv->DeleteLocalRef(js_number);
    138 }
    139 
    140 static void dtmf_cmd_callback(char dtmf) {
    141     CHECK_CALLBACK_ENV
    142     // TBD dtmf has changed from int to char
    143     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onSendDtmf, dtmf);
    144     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    145 }
    146 
    147 static void noice_reduction_callback(bthf_nrec_t nrec) {
    148     CHECK_CALLBACK_ENV
    149     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNoiceReductionEnable,
    150                                  nrec == BTHF_NREC_START);
    151     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    152 }
    153 
    154 static void at_chld_callback(bthf_chld_type_t chld) {
    155     CHECK_CALLBACK_ENV
    156     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtChld, chld);
    157     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    158 }
    159 
    160 static void at_cnum_callback() {
    161     CHECK_CALLBACK_ENV
    162     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtCnum);
    163     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    164 }
    165 
    166 static void at_cind_callback() {
    167     CHECK_CALLBACK_ENV
    168     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtCind);
    169     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    170 }
    171 
    172 static void at_cops_callback() {
    173     CHECK_CALLBACK_ENV
    174     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtCops);
    175     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    176 }
    177 
    178 static void at_clcc_callback() {
    179     CHECK_CALLBACK_ENV
    180     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtClcc);
    181     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    182 }
    183 
    184 static void unknown_at_callback(char *at_string) {
    185     CHECK_CALLBACK_ENV
    186     jstring js_at_string = sCallbackEnv->NewStringUTF(at_string);
    187     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onUnknownAt,
    188                                  js_at_string);
    189     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    190     sCallbackEnv->DeleteLocalRef(js_at_string);
    191 }
    192 
    193 static void key_pressed_callback() {
    194     CHECK_CALLBACK_ENV
    195     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onKeyPressed);
    196     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    197 }
    198 
    199 static bthf_callbacks_t sBluetoothHfpCallbacks = {
    200     sizeof(sBluetoothHfpCallbacks),
    201     connection_state_callback,
    202     audio_state_callback,
    203     voice_recognition_callback,
    204     answer_call_callback,
    205     hangup_call_callback,
    206     volume_control_callback,
    207     dial_call_callback,
    208     dtmf_cmd_callback,
    209     noice_reduction_callback,
    210     at_chld_callback,
    211     at_cnum_callback,
    212     at_cind_callback,
    213     at_cops_callback,
    214     at_clcc_callback,
    215     unknown_at_callback,
    216     key_pressed_callback
    217 };
    218 
    219 static void classInitNative(JNIEnv* env, jclass clazz) {
    220     int err;
    221     /*
    222     const bt_interface_t* btInf;
    223     bt_status_t status;
    224     */
    225 
    226     method_onConnectionStateChanged =
    227         env->GetMethodID(clazz, "onConnectionStateChanged", "(I[B)V");
    228     method_onAudioStateChanged = env->GetMethodID(clazz, "onAudioStateChanged", "(I[B)V");
    229     method_onVrStateChanged = env->GetMethodID(clazz, "onVrStateChanged", "(I)V");
    230     method_onAnswerCall = env->GetMethodID(clazz, "onAnswerCall", "()V");
    231     method_onHangupCall = env->GetMethodID(clazz, "onHangupCall", "()V");
    232     method_onVolumeChanged = env->GetMethodID(clazz, "onVolumeChanged", "(II)V");
    233     method_onDialCall = env->GetMethodID(clazz, "onDialCall", "(Ljava/lang/String;)V");
    234     method_onSendDtmf = env->GetMethodID(clazz, "onSendDtmf", "(I)V");
    235     method_onNoiceReductionEnable = env->GetMethodID(clazz, "onNoiceReductionEnable", "(Z)V");
    236     method_onAtChld = env->GetMethodID(clazz, "onAtChld", "(I)V");
    237     method_onAtCnum = env->GetMethodID(clazz, "onAtCnum", "()V");
    238     method_onAtCind = env->GetMethodID(clazz, "onAtCind", "()V");
    239     method_onAtCops = env->GetMethodID(clazz, "onAtCops", "()V");
    240     method_onAtClcc = env->GetMethodID(clazz, "onAtClcc", "()V");
    241     method_onUnknownAt = env->GetMethodID(clazz, "onUnknownAt", "(Ljava/lang/String;)V");
    242     method_onKeyPressed = env->GetMethodID(clazz, "onKeyPressed", "()V");
    243 
    244     /*
    245     if ( (btInf = getBluetoothInterface()) == NULL) {
    246         ALOGE("Bluetooth module is not loaded");
    247         return;
    248     }
    249 
    250     if ( (sBluetoothHfpInterface = (bthf_interface_t *)
    251           btInf->get_profile_interface(BT_PROFILE_HANDSFREE_ID)) == NULL) {
    252         ALOGE("Failed to get Bluetooth Handsfree Interface");
    253         return;
    254     }
    255 
    256     // TODO(BT) do this only once or
    257     //          Do we need to do this every time the BT reenables?
    258     if ( (status = sBluetoothHfpInterface->init(&sBluetoothHfpCallbacks)) != BT_STATUS_SUCCESS) {
    259         ALOGE("Failed to initialize Bluetooth HFP, status: %d", status);
    260         sBluetoothHfpInterface = NULL;
    261         return;
    262     }
    263     */
    264 
    265     ALOGI("%s: succeeds", __FUNCTION__);
    266 }
    267 
    268 static void initializeNative(JNIEnv *env, jobject object) {
    269     const bt_interface_t* btInf;
    270     bt_status_t status;
    271 
    272     if ( (btInf = getBluetoothInterface()) == NULL) {
    273         ALOGE("Bluetooth module is not loaded");
    274         return;
    275     }
    276 
    277     if (sBluetoothHfpInterface !=NULL) {
    278         ALOGW("Cleaning up Bluetooth Handsfree Interface before initializing...");
    279         sBluetoothHfpInterface->cleanup();
    280         sBluetoothHfpInterface = NULL;
    281     }
    282 
    283     if (mCallbacksObj != NULL) {
    284         ALOGW("Cleaning up Bluetooth Handsfree callback object");
    285         env->DeleteGlobalRef(mCallbacksObj);
    286         mCallbacksObj = NULL;
    287     }
    288 
    289     if ( (sBluetoothHfpInterface = (bthf_interface_t *)
    290           btInf->get_profile_interface(BT_PROFILE_HANDSFREE_ID)) == NULL) {
    291         ALOGE("Failed to get Bluetooth Handsfree Interface");
    292         return;
    293     }
    294 
    295     if ( (status = sBluetoothHfpInterface->init(&sBluetoothHfpCallbacks)) != BT_STATUS_SUCCESS) {
    296         ALOGE("Failed to initialize Bluetooth HFP, status: %d", status);
    297         sBluetoothHfpInterface = NULL;
    298         return;
    299     }
    300 
    301     mCallbacksObj = env->NewGlobalRef(object);
    302 }
    303 
    304 static void cleanupNative(JNIEnv *env, jobject object) {
    305     const bt_interface_t* btInf;
    306     bt_status_t status;
    307 
    308     if ( (btInf = getBluetoothInterface()) == NULL) {
    309         ALOGE("Bluetooth module is not loaded");
    310         return;
    311     }
    312 
    313     if (sBluetoothHfpInterface !=NULL) {
    314         ALOGW("Cleaning up Bluetooth Handsfree Interface...");
    315         sBluetoothHfpInterface->cleanup();
    316         sBluetoothHfpInterface = NULL;
    317     }
    318 
    319     if (mCallbacksObj != NULL) {
    320         ALOGW("Cleaning up Bluetooth Handsfree callback object");
    321         env->DeleteGlobalRef(mCallbacksObj);
    322         mCallbacksObj = NULL;
    323     }
    324 }
    325 
    326 static jboolean connectHfpNative(JNIEnv *env, jobject object, jbyteArray address) {
    327     jbyte *addr;
    328     bt_status_t status;
    329 
    330     ALOGI("%s: sBluetoothHfpInterface: %p", __FUNCTION__, sBluetoothHfpInterface);
    331     if (!sBluetoothHfpInterface) return JNI_FALSE;
    332 
    333     addr = env->GetByteArrayElements(address, NULL);
    334     if (!addr) {
    335         jniThrowIOException(env, EINVAL);
    336         return JNI_FALSE;
    337     }
    338 
    339     if ((status = sBluetoothHfpInterface->connect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
    340         ALOGE("Failed HF connection, status: %d", status);
    341     }
    342     env->ReleaseByteArrayElements(address, addr, 0);
    343     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    344 }
    345 
    346 static jboolean disconnectHfpNative(JNIEnv *env, jobject object, jbyteArray address) {
    347     jbyte *addr;
    348     bt_status_t status;
    349 
    350     if (!sBluetoothHfpInterface) return JNI_FALSE;
    351 
    352     addr = env->GetByteArrayElements(address, NULL);
    353     if (!addr) {
    354         jniThrowIOException(env, EINVAL);
    355         return JNI_FALSE;
    356     }
    357 
    358     if ( (status = sBluetoothHfpInterface->disconnect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
    359         ALOGE("Failed HF disconnection, status: %d", status);
    360     }
    361     env->ReleaseByteArrayElements(address, addr, 0);
    362     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    363 }
    364 
    365 static jboolean connectAudioNative(JNIEnv *env, jobject object, jbyteArray address) {
    366     jbyte *addr;
    367     bt_status_t status;
    368 
    369     if (!sBluetoothHfpInterface) return JNI_FALSE;
    370 
    371     addr = env->GetByteArrayElements(address, NULL);
    372     if (!addr) {
    373         jniThrowIOException(env, EINVAL);
    374         return JNI_FALSE;
    375     }
    376 
    377     if ( (status = sBluetoothHfpInterface->connect_audio((bt_bdaddr_t *)addr)) !=
    378          BT_STATUS_SUCCESS) {
    379         ALOGE("Failed HF audio 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 disconnectAudioNative(JNIEnv *env, jobject object, jbyteArray address) {
    386     jbyte *addr;
    387     bt_status_t status;
    388 
    389     if (!sBluetoothHfpInterface) 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 = sBluetoothHfpInterface->disconnect_audio((bt_bdaddr_t *) addr)) !=
    398          BT_STATUS_SUCCESS) {
    399         ALOGE("Failed HF audio 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 startVoiceRecognitionNative(JNIEnv *env, jobject object) {
    406     bt_status_t status;
    407     if (!sBluetoothHfpInterface) return JNI_FALSE;
    408 
    409     if ( (status = sBluetoothHfpInterface->start_voice_recognition()) != BT_STATUS_SUCCESS) {
    410         ALOGE("Failed to start voice recognition, status: %d", status);
    411     }
    412     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    413 }
    414 
    415 static jboolean stopVoiceRecognitionNative(JNIEnv *env, jobject object) {
    416     bt_status_t status;
    417     if (!sBluetoothHfpInterface) return JNI_FALSE;
    418 
    419     if ( (status = sBluetoothHfpInterface->stop_voice_recognition()) != BT_STATUS_SUCCESS) {
    420         ALOGE("Failed to stop voice recognition, status: %d", status);
    421     }
    422     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    423 }
    424 
    425 static jboolean setVolumeNative(JNIEnv *env, jobject object, jint volume_type, jint volume) {
    426     bt_status_t status;
    427     if (!sBluetoothHfpInterface) return JNI_FALSE;
    428 
    429     if ( (status = sBluetoothHfpInterface->volume_control((bthf_volume_type_t) volume_type,
    430                                                           volume)) != BT_STATUS_SUCCESS) {
    431         ALOGE("FAILED to control volume, status: %d", status);
    432     }
    433     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    434 }
    435 
    436 static jboolean notifyDeviceStatusNative(JNIEnv *env, jobject object,
    437                                          jint network_state, jint service_type, jint signal,
    438                                          jint battery_charge) {
    439     bt_status_t status;
    440     if (!sBluetoothHfpInterface) return JNI_FALSE;
    441 
    442     if ( (status = sBluetoothHfpInterface->device_status_notification
    443           ((bthf_network_state_t) network_state, (bthf_service_type_t) service_type,
    444            signal, battery_charge)) != BT_STATUS_SUCCESS) {
    445         ALOGE("FAILED to notify device status, status: %d", status);
    446     }
    447     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    448 }
    449 
    450 static jboolean copsResponseNative(JNIEnv *env, jobject object, jstring operator_str) {
    451     bt_status_t status;
    452     const char *operator_name;
    453     if (!sBluetoothHfpInterface) return JNI_FALSE;
    454 
    455     operator_name = env->GetStringUTFChars(operator_str, NULL);
    456 
    457     if ( (status = sBluetoothHfpInterface->cops_response(operator_name)) != BT_STATUS_SUCCESS) {
    458         ALOGE("Failed sending cops response, status: %d", status);
    459     }
    460     env->ReleaseStringUTFChars(operator_str, operator_name);
    461     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    462 }
    463 
    464 static jboolean cindResponseNative(JNIEnv *env, jobject object,
    465                                    jint service, jint num_active, jint num_held, jint call_state,
    466                                    jint signal, jint roam, jint battery_charge) {
    467     bt_status_t status;
    468     if (!sBluetoothHfpInterface) return JNI_FALSE;
    469 
    470     if ( (status = sBluetoothHfpInterface->cind_response(service, num_active, num_held,
    471                        (bthf_call_state_t) call_state,
    472                        signal, roam, battery_charge)) != BT_STATUS_SUCCESS) {
    473         ALOGE("Failed cind_response, status: %d", status);
    474     }
    475     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    476 }
    477 
    478 
    479 static jboolean atResponseStringNative(JNIEnv *env, jobject object, jstring response_str) {
    480     bt_status_t status;
    481     const char *response;
    482     if (!sBluetoothHfpInterface) return JNI_FALSE;
    483 
    484     response = env->GetStringUTFChars(response_str, NULL);
    485 
    486     if ( (status = sBluetoothHfpInterface->formatted_at_response(response)) != BT_STATUS_SUCCESS) {
    487         ALOGE("Failed formatted AT response, status: %d", status);
    488     }
    489     env->ReleaseStringUTFChars(response_str, response);
    490     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    491 }
    492 
    493 static jboolean atResponseCodeNative(JNIEnv *env, jobject object, jint response_code, jint cmee_code) {
    494     bt_status_t status;
    495     if (!sBluetoothHfpInterface) return JNI_FALSE;
    496 
    497     if ( (status = sBluetoothHfpInterface->at_response((bthf_at_response_t) response_code, cmee_code)) !=
    498          BT_STATUS_SUCCESS) {
    499         ALOGE("Failed AT response, status: %d", status);
    500     }
    501     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    502 }
    503 
    504 static jboolean clccResponseNative(JNIEnv *env, jobject object, jint index, jint dir,
    505                                    jint callStatus, jint mode, jboolean mpty, jstring number_str,
    506                                    jint type) {
    507     bt_status_t status;
    508     const char *number = NULL;
    509     if (!sBluetoothHfpInterface) return JNI_FALSE;
    510 
    511     if (number_str)
    512         number = env->GetStringUTFChars(number_str, NULL);
    513 
    514     if ( (status = sBluetoothHfpInterface->clcc_response(index, (bthf_call_direction_t) dir,
    515                      (bthf_call_state_t) callStatus,  (bthf_call_mode_t) mode,
    516                      mpty ? BTHF_CALL_MPTY_TYPE_MULTI : BTHF_CALL_MPTY_TYPE_SINGLE,
    517                      number, (bthf_call_addrtype_t) type)) != BT_STATUS_SUCCESS) {
    518         ALOGE("Failed sending CLCC response, status: %d", status);
    519     }
    520     if (number)
    521         env->ReleaseStringUTFChars(number_str, number);
    522     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    523 }
    524 
    525 static jboolean phoneStateChangeNative(JNIEnv *env, jobject object, jint num_active, jint num_held,
    526                                        jint call_state, jstring number_str, jint type) {
    527     bt_status_t status;
    528     const char *number;
    529     if (!sBluetoothHfpInterface) return JNI_FALSE;
    530 
    531     number = env->GetStringUTFChars(number_str, NULL);
    532 
    533     if ( (status = sBluetoothHfpInterface->phone_state_change(num_active, num_held,
    534                        (bthf_call_state_t) call_state, number,
    535                        (bthf_call_addrtype_t) type)) != BT_STATUS_SUCCESS) {
    536         ALOGE("Failed report phone state change, status: %d", status);
    537     }
    538     env->ReleaseStringUTFChars(number_str, number);
    539     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    540 }
    541 
    542 static JNINativeMethod sMethods[] = {
    543     {"classInitNative", "()V", (void *) classInitNative},
    544     {"initializeNative", "()V", (void *) initializeNative},
    545     {"cleanupNative", "()V", (void *) cleanupNative},
    546     {"connectHfpNative", "([B)Z", (void *) connectHfpNative},
    547     {"disconnectHfpNative", "([B)Z", (void *) disconnectHfpNative},
    548     {"connectAudioNative", "([B)Z", (void *) connectAudioNative},
    549     {"disconnectAudioNative", "([B)Z", (void *) disconnectAudioNative},
    550     {"startVoiceRecognitionNative", "()Z", (void *) startVoiceRecognitionNative},
    551     {"stopVoiceRecognitionNative", "()Z", (void *) stopVoiceRecognitionNative},
    552     {"setVolumeNative", "(II)Z", (void *) setVolumeNative},
    553     {"notifyDeviceStatusNative", "(IIII)Z", (void *) notifyDeviceStatusNative},
    554     {"copsResponseNative", "(Ljava/lang/String;)Z", (void *) copsResponseNative},
    555     {"cindResponseNative", "(IIIIIII)Z", (void *) cindResponseNative},
    556     {"atResponseStringNative", "(Ljava/lang/String;)Z", (void *) atResponseStringNative},
    557     {"atResponseCodeNative", "(II)Z", (void *)atResponseCodeNative},
    558     {"clccResponseNative", "(IIIIZLjava/lang/String;I)Z", (void *) clccResponseNative},
    559     {"phoneStateChangeNative", "(IIILjava/lang/String;I)Z", (void *) phoneStateChangeNative},
    560 };
    561 
    562 int register_com_android_bluetooth_hfp(JNIEnv* env)
    563 {
    564     return jniRegisterNativeMethods(env, "com/android/bluetooth/hfp/HeadsetStateMachine",
    565                                     sMethods, NELEM(sMethods));
    566 }
    567 
    568 } /* namespace android */
    569