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
34namespace android {
35
36static jmethodID method_onConnectionStateChanged;
37static jmethodID method_onAudioStateChanged;
38static jmethodID method_onVrStateChanged;
39static jmethodID method_onAnswerCall;
40static jmethodID method_onHangupCall;
41static jmethodID method_onVolumeChanged;
42static jmethodID method_onDialCall;
43static jmethodID method_onSendDtmf;
44static jmethodID method_onNoiceReductionEnable;
45static jmethodID method_onWBS;
46static jmethodID method_onAtChld;
47static jmethodID method_onAtCnum;
48static jmethodID method_onAtCind;
49static jmethodID method_onAtCops;
50static jmethodID method_onAtClcc;
51static jmethodID method_onUnknownAt;
52static jmethodID method_onKeyPressed;
53
54static const bthf_interface_t *sBluetoothHfpInterface = NULL;
55static jobject mCallbacksObj = NULL;
56static JNIEnv *sCallbackEnv = NULL;
57
58static bool checkCallbackThread() {
59    // Always fetch the latest callbackEnv from AdapterService.
60    // Caching this could cause this sCallbackEnv to go out-of-sync
61    // with the AdapterService's ENV if an ASSOCIATE/DISASSOCIATE event
62    // is received
63    //if (sCallbackEnv == NULL) {
64    sCallbackEnv = getCallbackEnv();
65    //}
66    JNIEnv* env = AndroidRuntime::getJNIEnv();
67    if (sCallbackEnv != env || sCallbackEnv == NULL) return false;
68    return true;
69}
70
71static jbyteArray marshall_bda(bt_bdaddr_t* bd_addr)
72{
73    jbyteArray addr;
74    addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
75    if (!addr) {
76        ALOGE("Fail to new jbyteArray bd addr");
77        checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
78        return NULL;
79    }
80    sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
81    return addr;
82}
83
84static void connection_state_callback(bthf_connection_state_t state, bt_bdaddr_t* bd_addr) {
85    jbyteArray addr;
86
87    ALOGI("%s", __FUNCTION__);
88
89    CHECK_CALLBACK_ENV
90    addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
91    if (!addr) {
92        ALOGE("Fail to new jbyteArray bd addr for connection state");
93        checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
94        return;
95    }
96
97    sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
98    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged,
99                                 (jint) state, addr);
100    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
101    sCallbackEnv->DeleteLocalRef(addr);
102}
103
104static void audio_state_callback(bthf_audio_state_t state, bt_bdaddr_t* bd_addr) {
105    jbyteArray addr;
106
107    CHECK_CALLBACK_ENV
108    addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
109    if (!addr) {
110        ALOGE("Fail to new jbyteArray bd addr for audio state");
111        checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
112        return;
113    }
114
115    sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
116    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioStateChanged, (jint) state, addr);
117    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
118    sCallbackEnv->DeleteLocalRef(addr);
119}
120
121static void voice_recognition_callback(bthf_vr_state_t state, bt_bdaddr_t* bd_addr) {
122    jbyteArray addr;
123
124    CHECK_CALLBACK_ENV
125    addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
126    if (!addr) {
127        ALOGE("Fail to new jbyteArray bd addr for audio state");
128        checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
129        return;
130    }
131
132    sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
133    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVrStateChanged, (jint) state, addr);
134    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
135    sCallbackEnv->DeleteLocalRef(addr);
136}
137
138static void answer_call_callback(bt_bdaddr_t* bd_addr) {
139    jbyteArray addr;
140
141    CHECK_CALLBACK_ENV
142    addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
143    if (!addr) {
144        ALOGE("Fail to new jbyteArray bd addr for audio state");
145        checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
146        return;
147    }
148
149    sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
150    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAnswerCall, addr);
151    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
152    sCallbackEnv->DeleteLocalRef(addr);
153}
154
155static void hangup_call_callback(bt_bdaddr_t* bd_addr) {
156    jbyteArray addr;
157
158    CHECK_CALLBACK_ENV
159    addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
160    if (!addr) {
161        ALOGE("Fail to new jbyteArray bd addr for audio state");
162        checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
163        return;
164    }
165
166    sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
167    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onHangupCall, addr);
168    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
169    sCallbackEnv->DeleteLocalRef(addr);
170}
171
172static void volume_control_callback(bthf_volume_type_t type, int volume, bt_bdaddr_t* bd_addr) {
173    jbyteArray addr;
174
175    CHECK_CALLBACK_ENV
176    addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
177    if (!addr) {
178        ALOGE("Fail to new jbyteArray bd addr for audio state");
179        checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
180        return;
181    }
182
183    sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
184    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVolumeChanged, (jint) type,
185                                                  (jint) volume, addr);
186    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
187    sCallbackEnv->DeleteLocalRef(addr);
188}
189
190static void dial_call_callback(char *number, bt_bdaddr_t* bd_addr) {
191    jbyteArray addr;
192
193    CHECK_CALLBACK_ENV
194    addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
195    if (!addr) {
196        ALOGE("Fail to new jbyteArray bd addr for audio state");
197        checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
198        return;
199    }
200
201    sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
202    jstring js_number = sCallbackEnv->NewStringUTF(number);
203    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onDialCall,
204                                 js_number, addr);
205    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
206    sCallbackEnv->DeleteLocalRef(js_number);
207    sCallbackEnv->DeleteLocalRef(addr);
208}
209
210static void dtmf_cmd_callback(char dtmf, bt_bdaddr_t* bd_addr) {
211    jbyteArray addr;
212
213    CHECK_CALLBACK_ENV
214    addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
215    if (!addr) {
216        ALOGE("Fail to new jbyteArray bd addr for audio state");
217        checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
218        return;
219    }
220
221    sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
222    // TBD dtmf has changed from int to char
223    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onSendDtmf, dtmf, addr);
224    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
225    sCallbackEnv->DeleteLocalRef(addr);
226}
227
228static void noice_reduction_callback(bthf_nrec_t nrec, bt_bdaddr_t* bd_addr) {
229    jbyteArray addr;
230
231    CHECK_CALLBACK_ENV
232    addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
233    if (!addr) {
234        ALOGE("Fail to new jbyteArray bd addr for audio state");
235        checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
236        return;
237    }
238    sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
239    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNoiceReductionEnable,
240                                 nrec == BTHF_NREC_START, addr);
241    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
242    sCallbackEnv->DeleteLocalRef(addr);
243}
244
245static void wbs_callback(bthf_wbs_config_t wbs_config, bt_bdaddr_t* bd_addr) {
246    jbyteArray addr;
247
248    CHECK_CALLBACK_ENV
249
250    if ((addr = marshall_bda(bd_addr)) == NULL)
251        return;
252
253    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onWBS, wbs_config, addr);
254    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
255    sCallbackEnv->DeleteLocalRef(addr);
256}
257
258static void at_chld_callback(bthf_chld_type_t chld, bt_bdaddr_t* bd_addr) {
259    jbyteArray addr;
260
261    CHECK_CALLBACK_ENV
262    addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
263    if (!addr) {
264        ALOGE("Fail to new jbyteArray bd addr for audio state");
265        checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
266        return;
267    }
268
269    sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
270    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtChld, chld, addr);
271    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
272    sCallbackEnv->DeleteLocalRef(addr);
273}
274
275static void at_cnum_callback(bt_bdaddr_t* bd_addr) {
276    jbyteArray addr;
277
278    CHECK_CALLBACK_ENV
279    addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
280    if (!addr) {
281        ALOGE("Fail to new jbyteArray bd addr for audio state");
282        checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
283        return;
284    }
285
286    sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
287    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtCnum, addr);
288    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
289    sCallbackEnv->DeleteLocalRef(addr);
290}
291
292static void at_cind_callback(bt_bdaddr_t* bd_addr) {
293    jbyteArray addr;
294
295    CHECK_CALLBACK_ENV
296    addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
297    if (!addr) {
298        ALOGE("Fail to new jbyteArray bd addr for audio state");
299        checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
300        return;
301    }
302
303    sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
304    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtCind, addr);
305    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
306    sCallbackEnv->DeleteLocalRef(addr);
307}
308
309static void at_cops_callback(bt_bdaddr_t* bd_addr) {
310    jbyteArray addr;
311
312    CHECK_CALLBACK_ENV
313    addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
314    if (!addr) {
315        ALOGE("Fail to new jbyteArray bd addr for audio state");
316        checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
317        return;
318    }
319
320    sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
321    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtCops, addr);
322    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
323    sCallbackEnv->DeleteLocalRef(addr);
324}
325
326static void at_clcc_callback(bt_bdaddr_t* bd_addr) {
327    jbyteArray addr;
328
329    CHECK_CALLBACK_ENV
330    addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
331    if (!addr) {
332        ALOGE("Fail to new jbyteArray bd addr for audio state");
333        checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
334        return;
335    }
336
337    sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
338    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtClcc, addr);
339    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
340    sCallbackEnv->DeleteLocalRef(addr);
341}
342
343static void unknown_at_callback(char *at_string, bt_bdaddr_t* bd_addr) {
344    jbyteArray addr;
345
346    CHECK_CALLBACK_ENV
347    addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
348    if (!addr) {
349        ALOGE("Fail to new jbyteArray bd addr for audio state");
350        checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
351        return;
352    }
353
354    sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
355    jstring js_at_string = sCallbackEnv->NewStringUTF(at_string);
356    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onUnknownAt,
357                                 js_at_string, addr);
358    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
359    sCallbackEnv->DeleteLocalRef(js_at_string);
360    sCallbackEnv->DeleteLocalRef(addr);
361}
362
363static void key_pressed_callback(bt_bdaddr_t* bd_addr) {
364    jbyteArray addr;
365
366    CHECK_CALLBACK_ENV
367    addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
368    if (!addr) {
369        ALOGE("Fail to new jbyteArray bd addr for audio state");
370        checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
371        return;
372    }
373
374    sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
375    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onKeyPressed, addr);
376    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
377    sCallbackEnv->DeleteLocalRef(addr);
378}
379
380static bthf_callbacks_t sBluetoothHfpCallbacks = {
381    sizeof(sBluetoothHfpCallbacks),
382    connection_state_callback,
383    audio_state_callback,
384    voice_recognition_callback,
385    answer_call_callback,
386    hangup_call_callback,
387    volume_control_callback,
388    dial_call_callback,
389    dtmf_cmd_callback,
390    noice_reduction_callback,
391    wbs_callback,
392    at_chld_callback,
393    at_cnum_callback,
394    at_cind_callback,
395    at_cops_callback,
396    at_clcc_callback,
397    unknown_at_callback,
398    key_pressed_callback
399};
400
401static void classInitNative(JNIEnv* env, jclass clazz) {
402    int err;
403    /*
404    const bt_interface_t* btInf;
405    bt_status_t status;
406    */
407
408    method_onConnectionStateChanged =
409        env->GetMethodID(clazz, "onConnectionStateChanged", "(I[B)V");
410    method_onAudioStateChanged = env->GetMethodID(clazz, "onAudioStateChanged", "(I[B)V");
411    method_onVrStateChanged = env->GetMethodID(clazz, "onVrStateChanged", "(I[B)V");
412    method_onAnswerCall = env->GetMethodID(clazz, "onAnswerCall", "([B)V");
413    method_onHangupCall = env->GetMethodID(clazz, "onHangupCall", "([B)V");
414    method_onVolumeChanged = env->GetMethodID(clazz, "onVolumeChanged", "(II[B)V");
415    method_onDialCall = env->GetMethodID(clazz, "onDialCall", "(Ljava/lang/String;[B)V");
416    method_onSendDtmf = env->GetMethodID(clazz, "onSendDtmf", "(I[B)V");
417    method_onNoiceReductionEnable = env->GetMethodID(clazz, "onNoiceReductionEnable", "(Z[B)V");
418    method_onWBS = env->GetMethodID(clazz,"onWBS","(I[B)V");
419    method_onAtChld = env->GetMethodID(clazz, "onAtChld", "(I[B)V");
420    method_onAtCnum = env->GetMethodID(clazz, "onAtCnum", "([B)V");
421    method_onAtCind = env->GetMethodID(clazz, "onAtCind", "([B)V");
422    method_onAtCops = env->GetMethodID(clazz, "onAtCops", "([B)V");
423    method_onAtClcc = env->GetMethodID(clazz, "onAtClcc", "([B)V");
424    method_onUnknownAt = env->GetMethodID(clazz, "onUnknownAt", "(Ljava/lang/String;[B)V");
425    method_onKeyPressed = env->GetMethodID(clazz, "onKeyPressed", "([B)V");
426
427    /*
428    if ( (btInf = getBluetoothInterface()) == NULL) {
429        ALOGE("Bluetooth module is not loaded");
430        return;
431    }
432
433    if ( (sBluetoothHfpInterface = (bthf_interface_t *)
434          btInf->get_profile_interface(BT_PROFILE_HANDSFREE_ID)) == NULL) {
435        ALOGE("Failed to get Bluetooth Handsfree Interface");
436        return;
437    }
438
439    // TODO(BT) do this only once or
440    //          Do we need to do this every time the BT reenables?
441    if ( (status = sBluetoothHfpInterface->init(&sBluetoothHfpCallbacks)) != BT_STATUS_SUCCESS) {
442        ALOGE("Failed to initialize Bluetooth HFP, status: %d", status);
443        sBluetoothHfpInterface = NULL;
444        return;
445    }
446    */
447
448    ALOGI("%s: succeeds", __FUNCTION__);
449}
450
451static void initializeNative(JNIEnv *env, jobject object, jint max_hf_clients) {
452    const bt_interface_t* btInf;
453    bt_status_t status;
454
455    if ( (btInf = getBluetoothInterface()) == NULL) {
456        ALOGE("Bluetooth module is not loaded");
457        return;
458    }
459
460    if (sBluetoothHfpInterface !=NULL) {
461        ALOGW("Cleaning up Bluetooth Handsfree Interface before initializing...");
462        sBluetoothHfpInterface->cleanup();
463        sBluetoothHfpInterface = NULL;
464    }
465
466    if (mCallbacksObj != NULL) {
467        ALOGW("Cleaning up Bluetooth Handsfree callback object");
468        env->DeleteGlobalRef(mCallbacksObj);
469        mCallbacksObj = NULL;
470    }
471
472    if ( (sBluetoothHfpInterface = (bthf_interface_t *)
473          btInf->get_profile_interface(BT_PROFILE_HANDSFREE_ID)) == NULL) {
474        ALOGE("Failed to get Bluetooth Handsfree Interface");
475        return;
476    }
477
478    if ( (status = sBluetoothHfpInterface->init(&sBluetoothHfpCallbacks,
479          max_hf_clients)) != BT_STATUS_SUCCESS) {
480        ALOGE("Failed to initialize Bluetooth HFP, status: %d", status);
481        sBluetoothHfpInterface = NULL;
482        return;
483    }
484
485    mCallbacksObj = env->NewGlobalRef(object);
486}
487
488static void cleanupNative(JNIEnv *env, jobject object) {
489    const bt_interface_t* btInf;
490    bt_status_t status;
491
492    if ( (btInf = getBluetoothInterface()) == NULL) {
493        ALOGE("Bluetooth module is not loaded");
494        return;
495    }
496
497    if (sBluetoothHfpInterface !=NULL) {
498        ALOGW("Cleaning up Bluetooth Handsfree Interface...");
499        sBluetoothHfpInterface->cleanup();
500        sBluetoothHfpInterface = NULL;
501    }
502
503    if (mCallbacksObj != NULL) {
504        ALOGW("Cleaning up Bluetooth Handsfree callback object");
505        env->DeleteGlobalRef(mCallbacksObj);
506        mCallbacksObj = NULL;
507    }
508}
509
510static jboolean connectHfpNative(JNIEnv *env, jobject object, jbyteArray address) {
511    jbyte *addr;
512    bt_status_t status;
513
514    ALOGI("%s: sBluetoothHfpInterface: %p", __FUNCTION__, sBluetoothHfpInterface);
515    if (!sBluetoothHfpInterface) return JNI_FALSE;
516
517    addr = env->GetByteArrayElements(address, NULL);
518    if (!addr) {
519        jniThrowIOException(env, EINVAL);
520        return JNI_FALSE;
521    }
522
523    if ((status = sBluetoothHfpInterface->connect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
524        ALOGE("Failed HF connection, status: %d", status);
525    }
526    env->ReleaseByteArrayElements(address, addr, 0);
527    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
528}
529
530static jboolean disconnectHfpNative(JNIEnv *env, jobject object, jbyteArray address) {
531    jbyte *addr;
532    bt_status_t status;
533
534    if (!sBluetoothHfpInterface) return JNI_FALSE;
535
536    addr = env->GetByteArrayElements(address, NULL);
537    if (!addr) {
538        jniThrowIOException(env, EINVAL);
539        return JNI_FALSE;
540    }
541
542    if ( (status = sBluetoothHfpInterface->disconnect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
543        ALOGE("Failed HF disconnection, status: %d", status);
544    }
545    env->ReleaseByteArrayElements(address, addr, 0);
546    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
547}
548
549static jboolean connectAudioNative(JNIEnv *env, jobject object, jbyteArray address) {
550    jbyte *addr;
551    bt_status_t status;
552
553    if (!sBluetoothHfpInterface) return JNI_FALSE;
554
555    addr = env->GetByteArrayElements(address, NULL);
556    if (!addr) {
557        jniThrowIOException(env, EINVAL);
558        return JNI_FALSE;
559    }
560
561    if ( (status = sBluetoothHfpInterface->connect_audio((bt_bdaddr_t *)addr)) !=
562         BT_STATUS_SUCCESS) {
563        ALOGE("Failed HF audio connection, status: %d", status);
564    }
565    env->ReleaseByteArrayElements(address, addr, 0);
566    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
567}
568
569static jboolean disconnectAudioNative(JNIEnv *env, jobject object, jbyteArray address) {
570    jbyte *addr;
571    bt_status_t status;
572
573    if (!sBluetoothHfpInterface) return JNI_FALSE;
574
575    addr = env->GetByteArrayElements(address, NULL);
576    if (!addr) {
577        jniThrowIOException(env, EINVAL);
578        return JNI_FALSE;
579    }
580
581    if ( (status = sBluetoothHfpInterface->disconnect_audio((bt_bdaddr_t *) addr)) !=
582         BT_STATUS_SUCCESS) {
583        ALOGE("Failed HF audio disconnection, status: %d", status);
584    }
585    env->ReleaseByteArrayElements(address, addr, 0);
586    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
587}
588
589static jboolean startVoiceRecognitionNative(JNIEnv *env, jobject object, jbyteArray address) {
590    jbyte *addr;
591    bt_status_t status;
592    if (!sBluetoothHfpInterface) return JNI_FALSE;
593
594    addr = env->GetByteArrayElements(address, NULL);
595    if (!addr) {
596        jniThrowIOException(env, EINVAL);
597        return JNI_FALSE;
598    }
599
600    if ( (status = sBluetoothHfpInterface->start_voice_recognition((bt_bdaddr_t *) addr))
601                                          != BT_STATUS_SUCCESS) {
602        ALOGE("Failed to start voice recognition, status: %d", status);
603    }
604    env->ReleaseByteArrayElements(address, addr, 0);
605    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
606}
607
608static jboolean stopVoiceRecognitionNative(JNIEnv *env, jobject object, jbyteArray address) {
609    jbyte *addr;
610    bt_status_t status;
611    if (!sBluetoothHfpInterface) return JNI_FALSE;
612
613    addr = env->GetByteArrayElements(address, NULL);
614    if (!addr) {
615        jniThrowIOException(env, EINVAL);
616        return JNI_FALSE;
617    }
618
619    if ( (status = sBluetoothHfpInterface->stop_voice_recognition((bt_bdaddr_t *) addr))
620                                     != BT_STATUS_SUCCESS) {
621        ALOGE("Failed to stop voice recognition, status: %d", status);
622    }
623    env->ReleaseByteArrayElements(address, addr, 0);
624    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
625}
626
627static jboolean setVolumeNative(JNIEnv *env, jobject object, jint volume_type,
628                                     jint volume, jbyteArray address) {
629    jbyte *addr;
630    bt_status_t status;
631    if (!sBluetoothHfpInterface) return JNI_FALSE;
632
633    addr = env->GetByteArrayElements(address, NULL);
634    if (!addr) {
635        jniThrowIOException(env, EINVAL);
636        return JNI_FALSE;
637    }
638
639    if ( (status = sBluetoothHfpInterface->volume_control((bthf_volume_type_t) volume_type,
640                                volume, (bt_bdaddr_t *) addr)) != BT_STATUS_SUCCESS) {
641        ALOGE("FAILED to control volume, status: %d", status);
642    }
643    env->ReleaseByteArrayElements(address, addr, 0);
644    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
645}
646
647static jboolean notifyDeviceStatusNative(JNIEnv *env, jobject object,
648                                         jint network_state, jint service_type, jint signal,
649                                         jint battery_charge) {
650    bt_status_t status;
651    if (!sBluetoothHfpInterface) return JNI_FALSE;
652
653    if ( (status = sBluetoothHfpInterface->device_status_notification
654          ((bthf_network_state_t) network_state, (bthf_service_type_t) service_type,
655           signal, battery_charge)) != BT_STATUS_SUCCESS) {
656        ALOGE("FAILED to notify device status, status: %d", status);
657    }
658    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
659}
660
661static jboolean copsResponseNative(JNIEnv *env, jobject object, jstring operator_str,
662                                              jbyteArray address) {
663    jbyte *addr;
664    bt_status_t status;
665    const char *operator_name;
666    if (!sBluetoothHfpInterface) return JNI_FALSE;
667
668    addr = env->GetByteArrayElements(address, NULL);
669    if (!addr) {
670        jniThrowIOException(env, EINVAL);
671        return JNI_FALSE;
672    }
673
674    operator_name = env->GetStringUTFChars(operator_str, NULL);
675
676    if ( (status = sBluetoothHfpInterface->cops_response(operator_name,(bt_bdaddr_t *) addr))
677                                                  != BT_STATUS_SUCCESS) {
678        ALOGE("Failed sending cops response, status: %d", status);
679    }
680    env->ReleaseByteArrayElements(address, addr, 0);
681    env->ReleaseStringUTFChars(operator_str, operator_name);
682    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
683}
684
685static jboolean cindResponseNative(JNIEnv *env, jobject object,
686                                   jint service, jint num_active, jint num_held, jint call_state,
687                                   jint signal, jint roam, jint battery_charge, jbyteArray address) {
688    jbyte *addr;
689    bt_status_t status;
690
691    ALOGI("%s: sBluetoothHfpInterface: %p", __FUNCTION__, sBluetoothHfpInterface);
692    if (!sBluetoothHfpInterface) return JNI_FALSE;
693
694    addr = env->GetByteArrayElements(address, NULL);
695    if (!addr) {
696        jniThrowIOException(env, EINVAL);
697        return JNI_FALSE;
698    }
699
700    if ( (status = sBluetoothHfpInterface->cind_response(service, num_active, num_held,
701                       (bthf_call_state_t) call_state,
702                       signal, roam, battery_charge, (bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
703        ALOGE("Failed cind_response, status: %d", status);
704    }
705    env->ReleaseByteArrayElements(address, addr, 0);
706    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
707}
708
709
710static jboolean atResponseStringNative(JNIEnv *env, jobject object, jstring response_str,
711                                                 jbyteArray address) {
712    jbyte *addr;
713    bt_status_t status;
714    const char *response;
715    if (!sBluetoothHfpInterface) return JNI_FALSE;
716
717    addr = env->GetByteArrayElements(address, NULL);
718    if (!addr) {
719        jniThrowIOException(env, EINVAL);
720        return JNI_FALSE;
721    }
722
723    response = env->GetStringUTFChars(response_str, NULL);
724
725    if ( (status = sBluetoothHfpInterface->formatted_at_response(response,
726                            (bt_bdaddr_t *)addr))!= BT_STATUS_SUCCESS) {
727        ALOGE("Failed formatted AT response, status: %d", status);
728    }
729    env->ReleaseByteArrayElements(address, addr, 0);
730    env->ReleaseStringUTFChars(response_str, response);
731    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
732}
733
734static jboolean atResponseCodeNative(JNIEnv *env, jobject object, jint response_code,
735                                             jint cmee_code, jbyteArray address) {
736    jbyte *addr;
737    bt_status_t status;
738    if (!sBluetoothHfpInterface) return JNI_FALSE;
739
740    addr = env->GetByteArrayElements(address, NULL);
741    if (!addr) {
742        jniThrowIOException(env, EINVAL);
743        return JNI_FALSE;
744    }
745
746    if ( (status = sBluetoothHfpInterface->at_response((bthf_at_response_t) response_code,
747              cmee_code, (bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
748        ALOGE("Failed AT response, status: %d", status);
749    }
750    env->ReleaseByteArrayElements(address, addr, 0);
751    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
752}
753
754static jboolean clccResponseNative(JNIEnv *env, jobject object, jint index, jint dir,
755                                   jint callStatus, jint mode, jboolean mpty, jstring number_str,
756                                   jint type, jbyteArray address) {
757    jbyte *addr;
758    bt_status_t status;
759    const char *number = NULL;
760    if (!sBluetoothHfpInterface) return JNI_FALSE;
761
762    addr = env->GetByteArrayElements(address, NULL);
763    if (!addr) {
764        jniThrowIOException(env, EINVAL);
765        return JNI_FALSE;
766    }
767
768    if (number_str)
769        number = env->GetStringUTFChars(number_str, NULL);
770
771    if ( (status = sBluetoothHfpInterface->clcc_response(index, (bthf_call_direction_t) dir,
772                (bthf_call_state_t) callStatus,  (bthf_call_mode_t) mode,
773                mpty ? BTHF_CALL_MPTY_TYPE_MULTI : BTHF_CALL_MPTY_TYPE_SINGLE,
774                number, (bthf_call_addrtype_t) type, (bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
775        ALOGE("Failed sending CLCC response, status: %d", status);
776    }
777    env->ReleaseByteArrayElements(address, addr, 0);
778    if (number)
779        env->ReleaseStringUTFChars(number_str, number);
780    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
781}
782
783static jboolean phoneStateChangeNative(JNIEnv *env, jobject object, jint num_active, jint num_held,
784                                       jint call_state, jstring number_str, jint type) {
785    bt_status_t status;
786    const char *number;
787    if (!sBluetoothHfpInterface) return JNI_FALSE;
788
789    number = env->GetStringUTFChars(number_str, NULL);
790
791    if ( (status = sBluetoothHfpInterface->phone_state_change(num_active, num_held,
792                       (bthf_call_state_t) call_state, number,
793                       (bthf_call_addrtype_t) type)) != BT_STATUS_SUCCESS) {
794        ALOGE("Failed report phone state change, status: %d", status);
795    }
796    env->ReleaseStringUTFChars(number_str, number);
797    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
798}
799
800
801static jboolean configureWBSNative(JNIEnv *env, jobject object, jbyteArray address,
802                                   jint codec_config) {
803    jbyte *addr;
804    bt_status_t status;
805
806    if (!sBluetoothHfpInterface) return JNI_FALSE;
807
808    addr = env->GetByteArrayElements(address, NULL);
809    if (!addr) {
810        jniThrowIOException(env, EINVAL);
811        return JNI_FALSE;
812    }
813
814    if ((status = sBluetoothHfpInterface->configure_wbs((bt_bdaddr_t *)addr,
815                   (bthf_wbs_config_t)codec_config)) != BT_STATUS_SUCCESS){
816        ALOGE("Failed HF WBS codec config, status: %d", status);
817    }
818    env->ReleaseByteArrayElements(address, addr, 0);
819    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
820}
821
822
823static JNINativeMethod sMethods[] = {
824    {"classInitNative", "()V", (void *) classInitNative},
825    {"initializeNative", "(I)V", (void *) initializeNative},
826    {"cleanupNative", "()V", (void *) cleanupNative},
827    {"connectHfpNative", "([B)Z", (void *) connectHfpNative},
828    {"disconnectHfpNative", "([B)Z", (void *) disconnectHfpNative},
829    {"connectAudioNative", "([B)Z", (void *) connectAudioNative},
830    {"disconnectAudioNative", "([B)Z", (void *) disconnectAudioNative},
831    {"startVoiceRecognitionNative", "([B)Z", (void *) startVoiceRecognitionNative},
832    {"stopVoiceRecognitionNative", "([B)Z", (void *) stopVoiceRecognitionNative},
833    {"setVolumeNative", "(II[B)Z", (void *) setVolumeNative},
834    {"notifyDeviceStatusNative", "(IIII)Z", (void *) notifyDeviceStatusNative},
835    {"copsResponseNative", "(Ljava/lang/String;[B)Z", (void *) copsResponseNative},
836    {"cindResponseNative", "(IIIIIII[B)Z", (void *) cindResponseNative},
837    {"atResponseStringNative", "(Ljava/lang/String;[B)Z", (void *) atResponseStringNative},
838    {"atResponseCodeNative", "(II[B)Z", (void *)atResponseCodeNative},
839    {"clccResponseNative", "(IIIIZLjava/lang/String;I[B)Z", (void *) clccResponseNative},
840    {"phoneStateChangeNative", "(IIILjava/lang/String;I)Z", (void *) phoneStateChangeNative},
841    {"configureWBSNative", "([BI)Z", (void *) configureWBSNative},
842};
843
844int register_com_android_bluetooth_hfp(JNIEnv* env)
845{
846    return jniRegisterNativeMethods(env, "com/android/bluetooth/hfp/HeadsetStateMachine",
847                                    sMethods, NELEM(sMethods));
848}
849
850} /* namespace android */
851