blob: 271df0ef53e607ec5a0dc409b29144eddeb04566 [file] [log] [blame]
Matthew Xie6c91bc02012-02-16 18:47:53 -08001/*
broodplank0c589302013-12-29 05:41:41 +01002 * Copyright (c) 2013, The Linux Foundation. All rights reserved.
3 * Not a Contribution.
4 *
Zhihai Xuede67c22012-10-23 17:01:01 -07005 * Copyright (C) 2012 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
Matthew Xie6c91bc02012-02-16 18:47:53 -080018 */
19
20#define LOG_TAG "BluetoothHeadsetServiceJni"
21
22#define LOG_NDEBUG 0
23
24#define CHECK_CALLBACK_ENV \
25 if (!checkCallbackThread()) { \
Matthew Xiec55a9832012-04-07 03:44:13 -070026 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);\
Matthew Xie6c91bc02012-02-16 18:47:53 -080027 return; \
28 }
29
30#include "com_android_bluetooth.h"
31#include "hardware/bt_hf.h"
32#include "utils/Log.h"
33#include "android_runtime/AndroidRuntime.h"
34
35#include <string.h>
36
37namespace android {
38
39static jmethodID method_onConnectionStateChanged;
40static jmethodID method_onAudioStateChanged;
41static jmethodID method_onVrStateChanged;
42static jmethodID method_onAnswerCall;
43static jmethodID method_onHangupCall;
44static jmethodID method_onVolumeChanged;
45static jmethodID method_onDialCall;
46static jmethodID method_onSendDtmf;
47static jmethodID method_onNoiceReductionEnable;
48static jmethodID method_onAtChld;
49static jmethodID method_onAtCnum;
50static jmethodID method_onAtCind;
51static jmethodID method_onAtCops;
52static jmethodID method_onAtClcc;
53static jmethodID method_onUnknownAt;
54static jmethodID method_onKeyPressed;
broodplank0c589302013-12-29 05:41:41 +010055static jmethodID method_onCodecNegotiated;
56
Matthew Xie6c91bc02012-02-16 18:47:53 -080057
58static const bthf_interface_t *sBluetoothHfpInterface = NULL;
59static jobject mCallbacksObj = NULL;
60static JNIEnv *sCallbackEnv = NULL;
61
62static bool checkCallbackThread() {
Kausik Sinnaswamy93f548f2012-03-21 15:14:32 +053063 // Always fetch the latest callbackEnv from AdapterService.
64 // Caching this could cause this sCallbackEnv to go out-of-sync
65 // with the AdapterService's ENV if an ASSOCIATE/DISASSOCIATE event
66 // is received
67 //if (sCallbackEnv == NULL) {
68 sCallbackEnv = getCallbackEnv();
69 //}
Matthew Xie6c91bc02012-02-16 18:47:53 -080070 JNIEnv* env = AndroidRuntime::getJNIEnv();
71 if (sCallbackEnv != env || sCallbackEnv == NULL) return false;
72 return true;
73}
74
75static void connection_state_callback(bthf_connection_state_t state, bt_bdaddr_t* bd_addr) {
76 jbyteArray addr;
77
Matthew Xiec55a9832012-04-07 03:44:13 -070078 ALOGI("%s", __FUNCTION__);
Matthew Xie6c91bc02012-02-16 18:47:53 -080079
80 CHECK_CALLBACK_ENV
81 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
82 if (!addr) {
Matthew Xiec55a9832012-04-07 03:44:13 -070083 ALOGE("Fail to new jbyteArray bd addr for connection state");
Matthew Xie6c91bc02012-02-16 18:47:53 -080084 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
85 return;
86 }
87
88 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
89 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged,
90 (jint) state, addr);
91 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
92 sCallbackEnv->DeleteLocalRef(addr);
93}
94
95static void audio_state_callback(bthf_audio_state_t state, bt_bdaddr_t* bd_addr) {
96 jbyteArray addr;
97
98 CHECK_CALLBACK_ENV
99 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
100 if (!addr) {
Matthew Xiec55a9832012-04-07 03:44:13 -0700101 ALOGE("Fail to new jbyteArray bd addr for audio state");
Matthew Xie6c91bc02012-02-16 18:47:53 -0800102 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
103 return;
104 }
105
106 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
107 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioStateChanged, (jint) state, addr);
108 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
109 sCallbackEnv->DeleteLocalRef(addr);
110}
111
112static void voice_recognition_callback(bthf_vr_state_t state) {
113 CHECK_CALLBACK_ENV
114 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVrStateChanged, (jint) state);
115 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
116}
117
118static void answer_call_callback() {
119 CHECK_CALLBACK_ENV
120 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAnswerCall);
121 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
122}
123
124static void hangup_call_callback() {
125 CHECK_CALLBACK_ENV
126 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onHangupCall);
127 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
128}
129
130static void volume_control_callback(bthf_volume_type_t type, int volume) {
131 CHECK_CALLBACK_ENV
132 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVolumeChanged, (jint) type, (jint) volume);
133 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
134}
135
136static void dial_call_callback(char *number) {
137 CHECK_CALLBACK_ENV
Syed Ibrahim M976912e2012-08-23 20:11:40 +0530138 jstring js_number = sCallbackEnv->NewStringUTF(number);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800139 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onDialCall,
Syed Ibrahim M976912e2012-08-23 20:11:40 +0530140 js_number);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800141 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
Syed Ibrahim M976912e2012-08-23 20:11:40 +0530142 sCallbackEnv->DeleteLocalRef(js_number);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800143}
144
145static void dtmf_cmd_callback(char dtmf) {
146 CHECK_CALLBACK_ENV
147 // TBD dtmf has changed from int to char
148 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onSendDtmf, dtmf);
149 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
150}
151
152static void noice_reduction_callback(bthf_nrec_t nrec) {
153 CHECK_CALLBACK_ENV
154 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNoiceReductionEnable,
155 nrec == BTHF_NREC_START);
156 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
157}
158
159static void at_chld_callback(bthf_chld_type_t chld) {
160 CHECK_CALLBACK_ENV
161 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtChld, chld);
162 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
163}
164
165static void at_cnum_callback() {
166 CHECK_CALLBACK_ENV
167 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtCnum);
168 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
169}
170
171static void at_cind_callback() {
172 CHECK_CALLBACK_ENV
173 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtCind);
174 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
175}
176
177static void at_cops_callback() {
178 CHECK_CALLBACK_ENV
179 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtCops);
180 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
181}
182
183static void at_clcc_callback() {
184 CHECK_CALLBACK_ENV
185 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtClcc);
186 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
187}
188
189static void unknown_at_callback(char *at_string) {
190 CHECK_CALLBACK_ENV
Syed Ibrahim M976912e2012-08-23 20:11:40 +0530191 jstring js_at_string = sCallbackEnv->NewStringUTF(at_string);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800192 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onUnknownAt,
Syed Ibrahim M976912e2012-08-23 20:11:40 +0530193 js_at_string);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800194 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
Syed Ibrahim M976912e2012-08-23 20:11:40 +0530195 sCallbackEnv->DeleteLocalRef(js_at_string);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800196}
197
198static void key_pressed_callback() {
199 CHECK_CALLBACK_ENV
200 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onKeyPressed);
201 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
202}
203
broodplank0c589302013-12-29 05:41:41 +0100204static void codec_negotiated_callback(int codec_type) {
205 CHECK_CALLBACK_ENV
206 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCodecNegotiated, (jint)codec_type);
207 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
208}
209
Matthew Xie6c91bc02012-02-16 18:47:53 -0800210static bthf_callbacks_t sBluetoothHfpCallbacks = {
211 sizeof(sBluetoothHfpCallbacks),
212 connection_state_callback,
213 audio_state_callback,
214 voice_recognition_callback,
215 answer_call_callback,
216 hangup_call_callback,
217 volume_control_callback,
218 dial_call_callback,
219 dtmf_cmd_callback,
220 noice_reduction_callback,
221 at_chld_callback,
222 at_cnum_callback,
223 at_cind_callback,
224 at_cops_callback,
225 at_clcc_callback,
226 unknown_at_callback,
broodplank0c589302013-12-29 05:41:41 +0100227 key_pressed_callback,
228 codec_negotiated_callback
Matthew Xie6c91bc02012-02-16 18:47:53 -0800229};
230
231static void classInitNative(JNIEnv* env, jclass clazz) {
232 int err;
fredc6654f5c2012-04-12 00:18:52 -0700233 /*
Matthew Xie6c91bc02012-02-16 18:47:53 -0800234 const bt_interface_t* btInf;
235 bt_status_t status;
fredc6654f5c2012-04-12 00:18:52 -0700236 */
Matthew Xie6c91bc02012-02-16 18:47:53 -0800237
238 method_onConnectionStateChanged =
239 env->GetMethodID(clazz, "onConnectionStateChanged", "(I[B)V");
240 method_onAudioStateChanged = env->GetMethodID(clazz, "onAudioStateChanged", "(I[B)V");
241 method_onVrStateChanged = env->GetMethodID(clazz, "onVrStateChanged", "(I)V");
242 method_onAnswerCall = env->GetMethodID(clazz, "onAnswerCall", "()V");
243 method_onHangupCall = env->GetMethodID(clazz, "onHangupCall", "()V");
244 method_onVolumeChanged = env->GetMethodID(clazz, "onVolumeChanged", "(II)V");
245 method_onDialCall = env->GetMethodID(clazz, "onDialCall", "(Ljava/lang/String;)V");
246 method_onSendDtmf = env->GetMethodID(clazz, "onSendDtmf", "(I)V");
247 method_onNoiceReductionEnable = env->GetMethodID(clazz, "onNoiceReductionEnable", "(Z)V");
248 method_onAtChld = env->GetMethodID(clazz, "onAtChld", "(I)V");
249 method_onAtCnum = env->GetMethodID(clazz, "onAtCnum", "()V");
250 method_onAtCind = env->GetMethodID(clazz, "onAtCind", "()V");
251 method_onAtCops = env->GetMethodID(clazz, "onAtCops", "()V");
252 method_onAtClcc = env->GetMethodID(clazz, "onAtClcc", "()V");
253 method_onUnknownAt = env->GetMethodID(clazz, "onUnknownAt", "(Ljava/lang/String;)V");
254 method_onKeyPressed = env->GetMethodID(clazz, "onKeyPressed", "()V");
broodplank0c589302013-12-29 05:41:41 +0100255 method_onCodecNegotiated = env->GetMethodID(clazz, "onCodecNegotiated", "(I)V");
Matthew Xie6c91bc02012-02-16 18:47:53 -0800256
fredc6654f5c2012-04-12 00:18:52 -0700257 /*
Matthew Xie6c91bc02012-02-16 18:47:53 -0800258 if ( (btInf = getBluetoothInterface()) == NULL) {
Matthew Xiec55a9832012-04-07 03:44:13 -0700259 ALOGE("Bluetooth module is not loaded");
Matthew Xie6c91bc02012-02-16 18:47:53 -0800260 return;
261 }
262
263 if ( (sBluetoothHfpInterface = (bthf_interface_t *)
264 btInf->get_profile_interface(BT_PROFILE_HANDSFREE_ID)) == NULL) {
Matthew Xiec55a9832012-04-07 03:44:13 -0700265 ALOGE("Failed to get Bluetooth Handsfree Interface");
Matthew Xie6c91bc02012-02-16 18:47:53 -0800266 return;
267 }
268
269 // TODO(BT) do this only once or
270 // Do we need to do this every time the BT reenables?
271 if ( (status = sBluetoothHfpInterface->init(&sBluetoothHfpCallbacks)) != BT_STATUS_SUCCESS) {
Matthew Xiec55a9832012-04-07 03:44:13 -0700272 ALOGE("Failed to initialize Bluetooth HFP, status: %d", status);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800273 sBluetoothHfpInterface = NULL;
274 return;
275 }
fredc6654f5c2012-04-12 00:18:52 -0700276 */
Matthew Xie6c91bc02012-02-16 18:47:53 -0800277
Matthew Xiec55a9832012-04-07 03:44:13 -0700278 ALOGI("%s: succeeds", __FUNCTION__);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800279}
280
fredc6654f5c2012-04-12 00:18:52 -0700281static void initializeNative(JNIEnv *env, jobject object) {
282 const bt_interface_t* btInf;
283 bt_status_t status;
284
285 if ( (btInf = getBluetoothInterface()) == NULL) {
Matthew Xiee469f162012-06-05 23:57:59 -0700286 ALOGE("Bluetooth module is not loaded");
fredc6654f5c2012-04-12 00:18:52 -0700287 return;
288 }
289
290 if (sBluetoothHfpInterface !=NULL) {
Matthew Xiee469f162012-06-05 23:57:59 -0700291 ALOGW("Cleaning up Bluetooth Handsfree Interface before initializing...");
fredc6654f5c2012-04-12 00:18:52 -0700292 sBluetoothHfpInterface->cleanup();
293 sBluetoothHfpInterface = NULL;
294 }
295
296 if (mCallbacksObj != NULL) {
Matthew Xiee469f162012-06-05 23:57:59 -0700297 ALOGW("Cleaning up Bluetooth Handsfree callback object");
fredc6654f5c2012-04-12 00:18:52 -0700298 env->DeleteGlobalRef(mCallbacksObj);
299 mCallbacksObj = NULL;
300 }
301
302 if ( (sBluetoothHfpInterface = (bthf_interface_t *)
303 btInf->get_profile_interface(BT_PROFILE_HANDSFREE_ID)) == NULL) {
Matthew Xiee469f162012-06-05 23:57:59 -0700304 ALOGE("Failed to get Bluetooth Handsfree Interface");
fredc6654f5c2012-04-12 00:18:52 -0700305 return;
306 }
307
308 if ( (status = sBluetoothHfpInterface->init(&sBluetoothHfpCallbacks)) != BT_STATUS_SUCCESS) {
Matthew Xiee469f162012-06-05 23:57:59 -0700309 ALOGE("Failed to initialize Bluetooth HFP, status: %d", status);
fredc6654f5c2012-04-12 00:18:52 -0700310 sBluetoothHfpInterface = NULL;
311 return;
312 }
313
Matthew Xie6c91bc02012-02-16 18:47:53 -0800314 mCallbacksObj = env->NewGlobalRef(object);
315}
316
broodplank0c589302013-12-29 05:41:41 +0100317static void initializeFeaturesNative(JNIEnv *env, jobject object, jint feature_bitmask) {
318 const bt_interface_t* btInf;
319 bt_status_t status;
320
321 if ( (btInf = getBluetoothInterface()) == NULL) {
322 ALOGE("Bluetooth module is not loaded");
323 return;
324 }
325 if (!sBluetoothHfpInterface) return ;
326 if (feature_bitmask)
327 if ((status = sBluetoothHfpInterface->init_features(feature_bitmask))
328 != BT_STATUS_SUCCESS){
329 ALOGE("Failed sending feature bitmask, status: %d", status);
330 }
331 return;
332}
333
fredc6654f5c2012-04-12 00:18:52 -0700334static void cleanupNative(JNIEnv *env, jobject object) {
335 const bt_interface_t* btInf;
336 bt_status_t status;
337
338 if ( (btInf = getBluetoothInterface()) == NULL) {
Matthew Xiee469f162012-06-05 23:57:59 -0700339 ALOGE("Bluetooth module is not loaded");
fredc6654f5c2012-04-12 00:18:52 -0700340 return;
341 }
342
343 if (sBluetoothHfpInterface !=NULL) {
Matthew Xiee469f162012-06-05 23:57:59 -0700344 ALOGW("Cleaning up Bluetooth Handsfree Interface...");
fredc6654f5c2012-04-12 00:18:52 -0700345 sBluetoothHfpInterface->cleanup();
346 sBluetoothHfpInterface = NULL;
347 }
348
349 if (mCallbacksObj != NULL) {
Matthew Xiee469f162012-06-05 23:57:59 -0700350 ALOGW("Cleaning up Bluetooth Handsfree callback object");
fredc6654f5c2012-04-12 00:18:52 -0700351 env->DeleteGlobalRef(mCallbacksObj);
352 mCallbacksObj = NULL;
353 }
354}
355
Matthew Xie6c91bc02012-02-16 18:47:53 -0800356static jboolean connectHfpNative(JNIEnv *env, jobject object, jbyteArray address) {
357 jbyte *addr;
Matthew Xie6c91bc02012-02-16 18:47:53 -0800358 bt_status_t status;
359
Matthew Xiec55a9832012-04-07 03:44:13 -0700360 ALOGI("%s: sBluetoothHfpInterface: %p", __FUNCTION__, sBluetoothHfpInterface);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800361 if (!sBluetoothHfpInterface) return JNI_FALSE;
362
363 addr = env->GetByteArrayElements(address, NULL);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800364 if (!addr) {
365 jniThrowIOException(env, EINVAL);
366 return JNI_FALSE;
367 }
368
369 if ((status = sBluetoothHfpInterface->connect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
Matthew Xiec55a9832012-04-07 03:44:13 -0700370 ALOGE("Failed HF connection, status: %d", status);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800371 }
372 env->ReleaseByteArrayElements(address, addr, 0);
373 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
374}
375
376static jboolean disconnectHfpNative(JNIEnv *env, jobject object, jbyteArray address) {
377 jbyte *addr;
378 bt_status_t status;
379
380 if (!sBluetoothHfpInterface) return JNI_FALSE;
381
382 addr = env->GetByteArrayElements(address, NULL);
383 if (!addr) {
384 jniThrowIOException(env, EINVAL);
385 return JNI_FALSE;
386 }
387
388 if ( (status = sBluetoothHfpInterface->disconnect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
Matthew Xiec55a9832012-04-07 03:44:13 -0700389 ALOGE("Failed HF disconnection, status: %d", status);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800390 }
391 env->ReleaseByteArrayElements(address, addr, 0);
392 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
393}
394
395static jboolean connectAudioNative(JNIEnv *env, jobject object, jbyteArray address) {
396 jbyte *addr;
397 bt_status_t status;
398
399 if (!sBluetoothHfpInterface) return JNI_FALSE;
400
401 addr = env->GetByteArrayElements(address, NULL);
402 if (!addr) {
403 jniThrowIOException(env, EINVAL);
404 return JNI_FALSE;
405 }
406
407 if ( (status = sBluetoothHfpInterface->connect_audio((bt_bdaddr_t *)addr)) !=
408 BT_STATUS_SUCCESS) {
Matthew Xiec55a9832012-04-07 03:44:13 -0700409 ALOGE("Failed HF audio connection, status: %d", status);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800410 }
411 env->ReleaseByteArrayElements(address, addr, 0);
412 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
413}
414
415static jboolean disconnectAudioNative(JNIEnv *env, jobject object, jbyteArray address) {
416 jbyte *addr;
417 bt_status_t status;
418
419 if (!sBluetoothHfpInterface) return JNI_FALSE;
420
421 addr = env->GetByteArrayElements(address, NULL);
422 if (!addr) {
423 jniThrowIOException(env, EINVAL);
424 return JNI_FALSE;
425 }
426
427 if ( (status = sBluetoothHfpInterface->disconnect_audio((bt_bdaddr_t *) addr)) !=
428 BT_STATUS_SUCCESS) {
Matthew Xiec55a9832012-04-07 03:44:13 -0700429 ALOGE("Failed HF audio disconnection, status: %d", status);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800430 }
431 env->ReleaseByteArrayElements(address, addr, 0);
432 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
433}
434
435static jboolean startVoiceRecognitionNative(JNIEnv *env, jobject object) {
436 bt_status_t status;
437 if (!sBluetoothHfpInterface) return JNI_FALSE;
438
439 if ( (status = sBluetoothHfpInterface->start_voice_recognition()) != BT_STATUS_SUCCESS) {
Matthew Xiec55a9832012-04-07 03:44:13 -0700440 ALOGE("Failed to start voice recognition, status: %d", status);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800441 }
442 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
443}
444
445static jboolean stopVoiceRecognitionNative(JNIEnv *env, jobject object) {
446 bt_status_t status;
447 if (!sBluetoothHfpInterface) return JNI_FALSE;
448
449 if ( (status = sBluetoothHfpInterface->stop_voice_recognition()) != BT_STATUS_SUCCESS) {
Matthew Xiec55a9832012-04-07 03:44:13 -0700450 ALOGE("Failed to stop voice recognition, status: %d", status);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800451 }
452 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
453}
454
455static jboolean setVolumeNative(JNIEnv *env, jobject object, jint volume_type, jint volume) {
456 bt_status_t status;
457 if (!sBluetoothHfpInterface) return JNI_FALSE;
458
459 if ( (status = sBluetoothHfpInterface->volume_control((bthf_volume_type_t) volume_type,
460 volume)) != BT_STATUS_SUCCESS) {
Matthew Xiec55a9832012-04-07 03:44:13 -0700461 ALOGE("FAILED to control volume, status: %d", status);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800462 }
463 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
464}
465
466static jboolean notifyDeviceStatusNative(JNIEnv *env, jobject object,
467 jint network_state, jint service_type, jint signal,
468 jint battery_charge) {
469 bt_status_t status;
470 if (!sBluetoothHfpInterface) return JNI_FALSE;
471
472 if ( (status = sBluetoothHfpInterface->device_status_notification
473 ((bthf_network_state_t) network_state, (bthf_service_type_t) service_type,
474 signal, battery_charge)) != BT_STATUS_SUCCESS) {
Matthew Xiec55a9832012-04-07 03:44:13 -0700475 ALOGE("FAILED to notify device status, status: %d", status);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800476 }
477 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
478}
479
480static jboolean copsResponseNative(JNIEnv *env, jobject object, jstring operator_str) {
481 bt_status_t status;
482 const char *operator_name;
483 if (!sBluetoothHfpInterface) return JNI_FALSE;
484
485 operator_name = env->GetStringUTFChars(operator_str, NULL);
486
487 if ( (status = sBluetoothHfpInterface->cops_response(operator_name)) != BT_STATUS_SUCCESS) {
Matthew Xiec55a9832012-04-07 03:44:13 -0700488 ALOGE("Failed sending cops response, status: %d", status);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800489 }
490 env->ReleaseStringUTFChars(operator_str, operator_name);
491 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
492}
493
494static jboolean cindResponseNative(JNIEnv *env, jobject object,
495 jint service, jint num_active, jint num_held, jint call_state,
496 jint signal, jint roam, jint battery_charge) {
497 bt_status_t status;
498 if (!sBluetoothHfpInterface) return JNI_FALSE;
499
500 if ( (status = sBluetoothHfpInterface->cind_response(service, num_active, num_held,
501 (bthf_call_state_t) call_state,
502 signal, roam, battery_charge)) != BT_STATUS_SUCCESS) {
Matthew Xiec55a9832012-04-07 03:44:13 -0700503 ALOGE("Failed cind_response, status: %d", status);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800504 }
505 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
506}
507
508
509static jboolean atResponseStringNative(JNIEnv *env, jobject object, jstring response_str) {
510 bt_status_t status;
511 const char *response;
512 if (!sBluetoothHfpInterface) return JNI_FALSE;
513
514 response = env->GetStringUTFChars(response_str, NULL);
515
516 if ( (status = sBluetoothHfpInterface->formatted_at_response(response)) != BT_STATUS_SUCCESS) {
Matthew Xiec55a9832012-04-07 03:44:13 -0700517 ALOGE("Failed formatted AT response, status: %d", status);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800518 }
519 env->ReleaseStringUTFChars(response_str, response);
520 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
521}
522
Sreenidhi T405b6142012-04-27 07:11:20 -0700523static jboolean atResponseCodeNative(JNIEnv *env, jobject object, jint response_code, jint cmee_code) {
Matthew Xie6c91bc02012-02-16 18:47:53 -0800524 bt_status_t status;
525 if (!sBluetoothHfpInterface) return JNI_FALSE;
526
Sreenidhi T405b6142012-04-27 07:11:20 -0700527 if ( (status = sBluetoothHfpInterface->at_response((bthf_at_response_t) response_code, cmee_code)) !=
Matthew Xie6c91bc02012-02-16 18:47:53 -0800528 BT_STATUS_SUCCESS) {
Matthew Xiec55a9832012-04-07 03:44:13 -0700529 ALOGE("Failed AT response, status: %d", status);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800530 }
531 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
532}
533
534static jboolean clccResponseNative(JNIEnv *env, jobject object, jint index, jint dir,
535 jint callStatus, jint mode, jboolean mpty, jstring number_str,
536 jint type) {
537 bt_status_t status;
Ravi Nagarajanbbbfba62012-04-18 14:45:27 +0530538 const char *number = NULL;
Matthew Xie6c91bc02012-02-16 18:47:53 -0800539 if (!sBluetoothHfpInterface) return JNI_FALSE;
540
Ravi Nagarajanbbbfba62012-04-18 14:45:27 +0530541 if (number_str)
542 number = env->GetStringUTFChars(number_str, NULL);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800543
544 if ( (status = sBluetoothHfpInterface->clcc_response(index, (bthf_call_direction_t) dir,
545 (bthf_call_state_t) callStatus, (bthf_call_mode_t) mode,
546 mpty ? BTHF_CALL_MPTY_TYPE_MULTI : BTHF_CALL_MPTY_TYPE_SINGLE,
547 number, (bthf_call_addrtype_t) type)) != BT_STATUS_SUCCESS) {
Matthew Xiec55a9832012-04-07 03:44:13 -0700548 ALOGE("Failed sending CLCC response, status: %d", status);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800549 }
Ravi Nagarajanbbbfba62012-04-18 14:45:27 +0530550 if (number)
551 env->ReleaseStringUTFChars(number_str, number);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800552 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
553}
554
555static jboolean phoneStateChangeNative(JNIEnv *env, jobject object, jint num_active, jint num_held,
556 jint call_state, jstring number_str, jint type) {
557 bt_status_t status;
558 const char *number;
559 if (!sBluetoothHfpInterface) return JNI_FALSE;
560
561 number = env->GetStringUTFChars(number_str, NULL);
562
563 if ( (status = sBluetoothHfpInterface->phone_state_change(num_active, num_held,
564 (bthf_call_state_t) call_state, number,
565 (bthf_call_addrtype_t) type)) != BT_STATUS_SUCCESS) {
Matthew Xiec55a9832012-04-07 03:44:13 -0700566 ALOGE("Failed report phone state change, status: %d", status);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800567 }
568 env->ReleaseStringUTFChars(number_str, number);
569 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
570}
571
572static JNINativeMethod sMethods[] = {
573 {"classInitNative", "()V", (void *) classInitNative},
fredc6654f5c2012-04-12 00:18:52 -0700574 {"initializeNative", "()V", (void *) initializeNative},
broodplank0c589302013-12-29 05:41:41 +0100575 {"initializeFeaturesNative", "(I)V", (void *) initializeFeaturesNative},
fredc6654f5c2012-04-12 00:18:52 -0700576 {"cleanupNative", "()V", (void *) cleanupNative},
Matthew Xie6c91bc02012-02-16 18:47:53 -0800577 {"connectHfpNative", "([B)Z", (void *) connectHfpNative},
578 {"disconnectHfpNative", "([B)Z", (void *) disconnectHfpNative},
579 {"connectAudioNative", "([B)Z", (void *) connectAudioNative},
580 {"disconnectAudioNative", "([B)Z", (void *) disconnectAudioNative},
581 {"startVoiceRecognitionNative", "()Z", (void *) startVoiceRecognitionNative},
582 {"stopVoiceRecognitionNative", "()Z", (void *) stopVoiceRecognitionNative},
583 {"setVolumeNative", "(II)Z", (void *) setVolumeNative},
584 {"notifyDeviceStatusNative", "(IIII)Z", (void *) notifyDeviceStatusNative},
585 {"copsResponseNative", "(Ljava/lang/String;)Z", (void *) copsResponseNative},
586 {"cindResponseNative", "(IIIIIII)Z", (void *) cindResponseNative},
587 {"atResponseStringNative", "(Ljava/lang/String;)Z", (void *) atResponseStringNative},
Sreenidhi T405b6142012-04-27 07:11:20 -0700588 {"atResponseCodeNative", "(II)Z", (void *)atResponseCodeNative},
Matthew Xie6c91bc02012-02-16 18:47:53 -0800589 {"clccResponseNative", "(IIIIZLjava/lang/String;I)Z", (void *) clccResponseNative},
590 {"phoneStateChangeNative", "(IIILjava/lang/String;I)Z", (void *) phoneStateChangeNative},
Matthew Xie6c91bc02012-02-16 18:47:53 -0800591};
592
593int register_com_android_bluetooth_hfp(JNIEnv* env)
594{
595 return jniRegisterNativeMethods(env, "com/android/bluetooth/hfp/HeadsetStateMachine",
596 sMethods, NELEM(sMethods));
597}
598
599} /* namespace android */