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
25 namespace android {
26
27 static bthf_client_interface_t* sBluetoothHfpClientInterface = NULL;
28 static jobject mCallbacksObj = NULL;
29
30 static jmethodID method_onConnectionStateChanged;
31 static jmethodID method_onAudioStateChanged;
32 static jmethodID method_onVrStateChanged;
33 static jmethodID method_onNetworkState;
34 static jmethodID method_onNetworkRoaming;
35 static jmethodID method_onNetworkSignal;
36 static jmethodID method_onBatteryLevel;
37 static jmethodID method_onCurrentOperator;
38 static jmethodID method_onCall;
39 static jmethodID method_onCallSetup;
40 static jmethodID method_onCallHeld;
41 static jmethodID method_onRespAndHold;
42 static jmethodID method_onClip;
43 static jmethodID method_onCallWaiting;
44 static jmethodID method_onCurrentCalls;
45 static jmethodID method_onVolumeChange;
46 static jmethodID method_onCmdResult;
47 static jmethodID method_onSubscriberInfo;
48 static jmethodID method_onInBandRing;
49 static jmethodID method_onLastVoiceTagNumber;
50 static jmethodID method_onRingIndication;
51 static jmethodID method_onUnknownEvent;
52
marshall_bda(const RawAddress * bd_addr)53 static jbyteArray marshall_bda(const RawAddress* bd_addr) {
54 CallbackEnv sCallbackEnv(__func__);
55 if (!sCallbackEnv.valid()) return NULL;
56
57 jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(RawAddress));
58 if (!addr) {
59 ALOGE("Fail to new jbyteArray bd addr");
60 return NULL;
61 }
62 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(RawAddress),
63 (jbyte*)bd_addr);
64 return addr;
65 }
66
connection_state_cb(const RawAddress * bd_addr,bthf_client_connection_state_t state,unsigned int peer_feat,unsigned int chld_feat)67 static void connection_state_cb(const RawAddress* bd_addr,
68 bthf_client_connection_state_t state,
69 unsigned int peer_feat,
70 unsigned int chld_feat) {
71 CallbackEnv sCallbackEnv(__func__);
72 if (!sCallbackEnv.valid()) return;
73
74 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
75 if (!addr.get()) return;
76
77 ALOGD("%s: state %d peer_feat %d chld_feat %d", __func__, state, peer_feat, chld_feat);
78 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged,
79 (jint)state, (jint)peer_feat, (jint)chld_feat,
80 addr.get());
81 }
82
audio_state_cb(const RawAddress * bd_addr,bthf_client_audio_state_t state)83 static void audio_state_cb(const RawAddress* bd_addr,
84 bthf_client_audio_state_t state) {
85 CallbackEnv sCallbackEnv(__func__);
86 if (!sCallbackEnv.valid()) return;
87
88 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
89 if (!addr.get()) return;
90
91 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioStateChanged,
92 (jint)state, addr.get());
93 }
94
vr_cmd_cb(const RawAddress * bd_addr,bthf_client_vr_state_t state)95 static void vr_cmd_cb(const RawAddress* bd_addr, bthf_client_vr_state_t state) {
96 CallbackEnv sCallbackEnv(__func__);
97 if (!sCallbackEnv.valid()) return;
98
99 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
100 if (!addr.get()) return;
101
102 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVrStateChanged,
103 (jint)state, addr.get());
104 }
105
network_state_cb(const RawAddress * bd_addr,bthf_client_network_state_t state)106 static void network_state_cb(const RawAddress* bd_addr,
107 bthf_client_network_state_t state) {
108 CallbackEnv sCallbackEnv(__func__);
109 if (!sCallbackEnv.valid()) return;
110
111 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
112 if (!addr.get()) return;
113
114 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNetworkState,
115 (jint)state, addr.get());
116 }
117
network_roaming_cb(const RawAddress * bd_addr,bthf_client_service_type_t type)118 static void network_roaming_cb(const RawAddress* bd_addr,
119 bthf_client_service_type_t type) {
120 CallbackEnv sCallbackEnv(__func__);
121
122 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
123 if (!addr.get()) return;
124
125 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNetworkRoaming,
126 (jint)type, addr.get());
127 }
128
network_signal_cb(const RawAddress * bd_addr,int signal)129 static void network_signal_cb(const RawAddress* bd_addr, int signal) {
130 CallbackEnv sCallbackEnv(__func__);
131 if (!sCallbackEnv.valid()) return;
132
133 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
134 if (!addr.get()) return;
135
136 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNetworkSignal,
137 (jint)signal, addr.get());
138 }
139
battery_level_cb(const RawAddress * bd_addr,int level)140 static void battery_level_cb(const RawAddress* bd_addr, int level) {
141 CallbackEnv sCallbackEnv(__func__);
142 if (!sCallbackEnv.valid()) return;
143
144 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
145 if (!addr.get()) return;
146
147 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onBatteryLevel,
148 (jint)level, addr.get());
149 }
150
current_operator_cb(const RawAddress * bd_addr,const char * name)151 static void current_operator_cb(const RawAddress* bd_addr, const char* name) {
152 CallbackEnv sCallbackEnv(__func__);
153 if (!sCallbackEnv.valid()) return;
154
155 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
156 if (!addr.get()) return;
157
158 const char null_str[] = "";
159 if (!sCallbackEnv.isValidUtf(name)) {
160 android_errorWriteLog(0x534e4554, "109838537");
161 ALOGE("%s: name is not a valid UTF string.", __func__);
162 name = null_str;
163 }
164
165 ScopedLocalRef<jstring> js_name(sCallbackEnv.get(),
166 sCallbackEnv->NewStringUTF(name));
167 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCurrentOperator,
168 js_name.get(), addr.get());
169 }
170
call_cb(const RawAddress * bd_addr,bthf_client_call_t call)171 static void call_cb(const RawAddress* bd_addr, bthf_client_call_t call) {
172 CallbackEnv sCallbackEnv(__func__);
173 if (!sCallbackEnv.valid()) return;
174
175 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
176 if (!addr.get()) return;
177
178 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCall, (jint)call,
179 addr.get());
180 }
181
callsetup_cb(const RawAddress * bd_addr,bthf_client_callsetup_t callsetup)182 static void callsetup_cb(const RawAddress* bd_addr,
183 bthf_client_callsetup_t callsetup) {
184 CallbackEnv sCallbackEnv(__func__);
185 if (!sCallbackEnv.valid()) return;
186
187 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
188 if (!addr.get()) return;
189
190 ALOGD("callsetup_cb bdaddr %02x:%02x:%02x:%02x:%02x:%02x",
191 bd_addr->address[0], bd_addr->address[1], bd_addr->address[2],
192 bd_addr->address[3], bd_addr->address[4], bd_addr->address[5]);
193
194 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCallSetup,
195 (jint)callsetup, addr.get());
196 }
197
callheld_cb(const RawAddress * bd_addr,bthf_client_callheld_t callheld)198 static void callheld_cb(const RawAddress* bd_addr,
199 bthf_client_callheld_t callheld) {
200 CallbackEnv sCallbackEnv(__func__);
201 if (!sCallbackEnv.valid()) return;
202
203 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
204 if (!addr.get()) return;
205
206 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCallHeld, (jint)callheld,
207 addr.get());
208 }
209
resp_and_hold_cb(const RawAddress * bd_addr,bthf_client_resp_and_hold_t resp_and_hold)210 static void resp_and_hold_cb(const RawAddress* bd_addr,
211 bthf_client_resp_and_hold_t resp_and_hold) {
212 CallbackEnv sCallbackEnv(__func__);
213 if (!sCallbackEnv.valid()) return;
214
215 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
216 if (!addr.get()) return;
217
218 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onRespAndHold,
219 (jint)resp_and_hold, addr.get());
220 }
221
clip_cb(const RawAddress * bd_addr,const char * number)222 static void clip_cb(const RawAddress* bd_addr, const char* number) {
223 CallbackEnv sCallbackEnv(__func__);
224 if (!sCallbackEnv.valid()) return;
225
226 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
227 if (!addr.get()) return;
228
229 const char null_str[] = "";
230 if (!sCallbackEnv.isValidUtf(number)) {
231 android_errorWriteLog(0x534e4554, "109838537");
232 ALOGE("%s: number is not a valid UTF string.", __func__);
233 number = null_str;
234 }
235
236 ScopedLocalRef<jstring> js_number(sCallbackEnv.get(),
237 sCallbackEnv->NewStringUTF(number));
238 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onClip, js_number.get(),
239 addr.get());
240 }
241
call_waiting_cb(const RawAddress * bd_addr,const char * number)242 static void call_waiting_cb(const RawAddress* bd_addr, const char* number) {
243 CallbackEnv sCallbackEnv(__func__);
244 if (!sCallbackEnv.valid()) return;
245
246 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
247 if (!addr.get()) return;
248
249 const char null_str[] = "";
250 if (!sCallbackEnv.isValidUtf(number)) {
251 android_errorWriteLog(0x534e4554, "109838537");
252 ALOGE("%s: number is not a valid UTF string.", __func__);
253 number = null_str;
254 }
255
256 ScopedLocalRef<jstring> js_number(sCallbackEnv.get(),
257 sCallbackEnv->NewStringUTF(number));
258 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCallWaiting,
259 js_number.get(), addr.get());
260 }
261
current_calls_cb(const RawAddress * bd_addr,int index,bthf_client_call_direction_t dir,bthf_client_call_state_t state,bthf_client_call_mpty_type_t mpty,const char * number)262 static void current_calls_cb(const RawAddress* bd_addr, int index,
263 bthf_client_call_direction_t dir,
264 bthf_client_call_state_t state,
265 bthf_client_call_mpty_type_t mpty,
266 const char* number) {
267 CallbackEnv sCallbackEnv(__func__);
268 if (!sCallbackEnv.valid()) return;
269
270 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
271 if (!addr.get()) return;
272
273 const char null_str[] = "";
274 if (!sCallbackEnv.isValidUtf(number)) {
275 android_errorWriteLog(0x534e4554, "109838537");
276 ALOGE("%s: number is not a valid UTF string.", __func__);
277 number = null_str;
278 }
279
280 ScopedLocalRef<jstring> js_number(sCallbackEnv.get(),
281 sCallbackEnv->NewStringUTF(number));
282 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCurrentCalls, index, dir,
283 state, mpty, js_number.get(), addr.get());
284 }
285
volume_change_cb(const RawAddress * bd_addr,bthf_client_volume_type_t type,int volume)286 static void volume_change_cb(const RawAddress* bd_addr,
287 bthf_client_volume_type_t type, int volume) {
288 CallbackEnv sCallbackEnv(__func__);
289 if (!sCallbackEnv.valid()) return;
290
291 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
292 if (!addr.get()) return;
293 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVolumeChange, (jint)type,
294 (jint)volume, addr.get());
295 }
296
cmd_complete_cb(const RawAddress * bd_addr,bthf_client_cmd_complete_t type,int cme)297 static void cmd_complete_cb(const RawAddress* bd_addr,
298 bthf_client_cmd_complete_t type, int cme) {
299 CallbackEnv sCallbackEnv(__func__);
300 if (!sCallbackEnv.valid()) return;
301
302 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
303 if (!addr.get()) return;
304 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCmdResult, (jint)type,
305 (jint)cme, addr.get());
306 }
307
subscriber_info_cb(const RawAddress * bd_addr,const char * name,bthf_client_subscriber_service_type_t type)308 static void subscriber_info_cb(const RawAddress* bd_addr, const char* name,
309 bthf_client_subscriber_service_type_t type) {
310 CallbackEnv sCallbackEnv(__func__);
311 if (!sCallbackEnv.valid()) return;
312
313 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
314 if (!addr.get()) return;
315
316 const char null_str[] = "";
317 if (!sCallbackEnv.isValidUtf(name)) {
318 android_errorWriteLog(0x534e4554, "109838537");
319 ALOGE("%s: name is not a valid UTF string.", __func__);
320 name = null_str;
321 }
322
323 ScopedLocalRef<jstring> js_name(sCallbackEnv.get(),
324 sCallbackEnv->NewStringUTF(name));
325 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onSubscriberInfo,
326 js_name.get(), (jint)type, addr.get());
327 }
328
in_band_ring_cb(const RawAddress * bd_addr,bthf_client_in_band_ring_state_t in_band)329 static void in_band_ring_cb(const RawAddress* bd_addr,
330 bthf_client_in_band_ring_state_t in_band) {
331 CallbackEnv sCallbackEnv(__func__);
332 if (!sCallbackEnv.valid()) return;
333
334 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
335 if (!addr.get()) return;
336 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onInBandRing,
337 (jint)in_band, addr.get());
338 }
339
last_voice_tag_number_cb(const RawAddress * bd_addr,const char * number)340 static void last_voice_tag_number_cb(const RawAddress* bd_addr,
341 const char* number) {
342 CallbackEnv sCallbackEnv(__func__);
343 if (!sCallbackEnv.valid()) return;
344
345 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
346 if (!addr.get()) return;
347
348 const char null_str[] = "";
349 if (!sCallbackEnv.isValidUtf(number)) {
350 android_errorWriteLog(0x534e4554, "109838537");
351 ALOGE("%s: number is not a valid UTF string.", __func__);
352 number = null_str;
353 }
354
355 ScopedLocalRef<jstring> js_number(sCallbackEnv.get(),
356 sCallbackEnv->NewStringUTF(number));
357 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onLastVoiceTagNumber,
358 js_number.get(), addr.get());
359 }
360
ring_indication_cb(const RawAddress * bd_addr)361 static void ring_indication_cb(const RawAddress* bd_addr) {
362 CallbackEnv sCallbackEnv(__func__);
363 if (!sCallbackEnv.valid()) return;
364
365 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
366 if (!addr.get()) return;
367 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onRingIndication,
368 addr.get());
369 }
370
unknown_event_cb(const RawAddress * bd_addr,const char * eventString)371 static void unknown_event_cb(const RawAddress* bd_addr,
372 const char* eventString) {
373 CallbackEnv sCallbackEnv(__func__);
374 if (!sCallbackEnv.valid()) return;
375
376 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
377 if (!addr.get()) return;
378
379 ScopedLocalRef<jstring> js_event(sCallbackEnv.get(),
380 sCallbackEnv->NewStringUTF(eventString));
381 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onUnknownEvent,
382 js_event.get(), addr.get());
383 }
384
385 static bthf_client_callbacks_t sBluetoothHfpClientCallbacks = {
386 sizeof(sBluetoothHfpClientCallbacks),
387 connection_state_cb,
388 audio_state_cb,
389 vr_cmd_cb,
390 network_state_cb,
391 network_roaming_cb,
392 network_signal_cb,
393 battery_level_cb,
394 current_operator_cb,
395 call_cb,
396 callsetup_cb,
397 callheld_cb,
398 resp_and_hold_cb,
399 clip_cb,
400 call_waiting_cb,
401 current_calls_cb,
402 volume_change_cb,
403 cmd_complete_cb,
404 subscriber_info_cb,
405 in_band_ring_cb,
406 last_voice_tag_number_cb,
407 ring_indication_cb,
408 unknown_event_cb,
409 };
410
classInitNative(JNIEnv * env,jclass clazz)411 static void classInitNative(JNIEnv* env, jclass clazz) {
412 method_onConnectionStateChanged =
413 env->GetMethodID(clazz, "onConnectionStateChanged", "(III[B)V");
414 method_onAudioStateChanged =
415 env->GetMethodID(clazz, "onAudioStateChanged", "(I[B)V");
416 method_onVrStateChanged =
417 env->GetMethodID(clazz, "onVrStateChanged", "(I[B)V");
418 method_onNetworkState = env->GetMethodID(clazz, "onNetworkState", "(I[B)V");
419 method_onNetworkRoaming = env->GetMethodID(clazz, "onNetworkRoaming", "(I[B)V");
420 method_onNetworkSignal = env->GetMethodID(clazz, "onNetworkSignal", "(I[B)V");
421 method_onBatteryLevel = env->GetMethodID(clazz, "onBatteryLevel", "(I[B)V");
422 method_onCurrentOperator =
423 env->GetMethodID(clazz, "onCurrentOperator", "(Ljava/lang/String;[B)V");
424 method_onCall = env->GetMethodID(clazz, "onCall", "(I[B)V");
425 method_onCallSetup = env->GetMethodID(clazz, "onCallSetup", "(I[B)V");
426 method_onCallHeld = env->GetMethodID(clazz, "onCallHeld", "(I[B)V");
427 method_onRespAndHold = env->GetMethodID(clazz, "onRespAndHold", "(I[B)V");
428 method_onClip = env->GetMethodID(clazz, "onClip", "(Ljava/lang/String;[B)V");
429 method_onCallWaiting =
430 env->GetMethodID(clazz, "onCallWaiting", "(Ljava/lang/String;[B)V");
431 method_onCurrentCalls =
432 env->GetMethodID(clazz, "onCurrentCalls", "(IIIILjava/lang/String;[B)V");
433 method_onVolumeChange = env->GetMethodID(clazz, "onVolumeChange", "(II[B)V");
434 method_onCmdResult = env->GetMethodID(clazz, "onCmdResult", "(II[B)V");
435 method_onSubscriberInfo =
436 env->GetMethodID(clazz, "onSubscriberInfo", "(Ljava/lang/String;I[B)V");
437 method_onInBandRing = env->GetMethodID(clazz, "onInBandRing", "(I[B)V");
438 method_onLastVoiceTagNumber =
439 env->GetMethodID(clazz, "onLastVoiceTagNumber", "(Ljava/lang/String;[B)V");
440 method_onRingIndication = env->GetMethodID(clazz, "onRingIndication", "([B)V");
441 method_onUnknownEvent =
442 env->GetMethodID(clazz, "onUnknownEvent", "(Ljava/lang/String;[B)V");
443
444 ALOGI("%s succeeds", __func__);
445 }
446
initializeNative(JNIEnv * env,jobject object)447 static void initializeNative(JNIEnv* env, jobject object) {
448 ALOGD("%s: HfpClient", __func__);
449 const bt_interface_t* btInf = getBluetoothInterface();
450 if (btInf == NULL) {
451 ALOGE("Bluetooth module is not loaded");
452 return;
453 }
454
455 if (sBluetoothHfpClientInterface != NULL) {
456 ALOGW("Cleaning up Bluetooth HFP Client Interface before initializing");
457 sBluetoothHfpClientInterface->cleanup();
458 sBluetoothHfpClientInterface = NULL;
459 }
460
461 if (mCallbacksObj != NULL) {
462 ALOGW("Cleaning up Bluetooth HFP Client callback object");
463 env->DeleteGlobalRef(mCallbacksObj);
464 mCallbacksObj = NULL;
465 }
466
467 sBluetoothHfpClientInterface =
468 (bthf_client_interface_t*)btInf->get_profile_interface(
469 BT_PROFILE_HANDSFREE_CLIENT_ID);
470 if (sBluetoothHfpClientInterface == NULL) {
471 ALOGE("Failed to get Bluetooth HFP Client Interface");
472 return;
473 }
474
475 bt_status_t status =
476 sBluetoothHfpClientInterface->init(&sBluetoothHfpClientCallbacks);
477 if (status != BT_STATUS_SUCCESS) {
478 ALOGE("Failed to initialize Bluetooth HFP Client, status: %d", status);
479 sBluetoothHfpClientInterface = NULL;
480 return;
481 }
482
483 mCallbacksObj = env->NewGlobalRef(object);
484 }
485
cleanupNative(JNIEnv * env,jobject object)486 static void cleanupNative(JNIEnv* env, jobject object) {
487 const bt_interface_t* btInf = getBluetoothInterface();
488 if (btInf == NULL) {
489 ALOGE("Bluetooth module is not loaded");
490 return;
491 }
492
493 if (sBluetoothHfpClientInterface != NULL) {
494 ALOGW("Cleaning up Bluetooth HFP Client Interface...");
495 sBluetoothHfpClientInterface->cleanup();
496 sBluetoothHfpClientInterface = NULL;
497 }
498
499 if (mCallbacksObj != NULL) {
500 ALOGW("Cleaning up Bluetooth HFP Client callback object");
501 env->DeleteGlobalRef(mCallbacksObj);
502 mCallbacksObj = NULL;
503 }
504 }
505
connectNative(JNIEnv * env,jobject object,jbyteArray address)506 static jboolean connectNative(JNIEnv* env, jobject object, jbyteArray address) {
507 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
508
509 jbyte* addr = env->GetByteArrayElements(address, NULL);
510 if (!addr) {
511 jniThrowIOException(env, EINVAL);
512 return JNI_FALSE;
513 }
514
515 bt_status_t status = sBluetoothHfpClientInterface->connect((RawAddress*)addr);
516 if (status != BT_STATUS_SUCCESS) {
517 ALOGE("Failed AG connection, status: %d", status);
518 }
519 env->ReleaseByteArrayElements(address, addr, 0);
520 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
521 }
522
disconnectNative(JNIEnv * env,jobject object,jbyteArray address)523 static jboolean disconnectNative(JNIEnv* env, jobject object,
524 jbyteArray address) {
525 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
526
527 jbyte* addr = env->GetByteArrayElements(address, NULL);
528 if (!addr) {
529 jniThrowIOException(env, EINVAL);
530 return JNI_FALSE;
531 }
532
533 bt_status_t status =
534 sBluetoothHfpClientInterface->disconnect((const RawAddress*)addr);
535 if (status != BT_STATUS_SUCCESS) {
536 ALOGE("Failed AG disconnection, status: %d", status);
537 }
538 env->ReleaseByteArrayElements(address, addr, 0);
539 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
540 }
541
connectAudioNative(JNIEnv * env,jobject object,jbyteArray address)542 static jboolean connectAudioNative(JNIEnv* env, jobject object,
543 jbyteArray address) {
544 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
545
546 jbyte* addr = env->GetByteArrayElements(address, NULL);
547 if (!addr) {
548 jniThrowIOException(env, EINVAL);
549 return JNI_FALSE;
550 }
551
552 bt_status_t status =
553 sBluetoothHfpClientInterface->connect_audio((const RawAddress*)addr);
554 if (status != BT_STATUS_SUCCESS) {
555 ALOGE("Failed AG audio connection, status: %d", status);
556 }
557 env->ReleaseByteArrayElements(address, addr, 0);
558 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
559 }
560
disconnectAudioNative(JNIEnv * env,jobject object,jbyteArray address)561 static jboolean disconnectAudioNative(JNIEnv* env, jobject object,
562 jbyteArray address) {
563 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
564
565 jbyte* addr = env->GetByteArrayElements(address, NULL);
566 if (!addr) {
567 jniThrowIOException(env, EINVAL);
568 return JNI_FALSE;
569 }
570
571 bt_status_t status =
572 sBluetoothHfpClientInterface->disconnect_audio((const RawAddress*)addr);
573 if (status != BT_STATUS_SUCCESS) {
574 ALOGE("Failed AG audio disconnection, status: %d", status);
575 }
576 env->ReleaseByteArrayElements(address, addr, 0);
577 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
578 }
579
startVoiceRecognitionNative(JNIEnv * env,jobject object,jbyteArray address)580 static jboolean startVoiceRecognitionNative(JNIEnv* env, jobject object,
581 jbyteArray address) {
582 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
583
584 jbyte* addr = env->GetByteArrayElements(address, NULL);
585 if (!addr) {
586 jniThrowIOException(env, EINVAL);
587 return JNI_FALSE;
588 }
589
590 bt_status_t status = sBluetoothHfpClientInterface->start_voice_recognition(
591 (const RawAddress*)addr);
592 if (status != BT_STATUS_SUCCESS) {
593 ALOGE("Failed to start voice recognition, status: %d", status);
594 }
595 env->ReleaseByteArrayElements(address, addr, 0);
596 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
597 }
598
stopVoiceRecognitionNative(JNIEnv * env,jobject object,jbyteArray address)599 static jboolean stopVoiceRecognitionNative(JNIEnv* env, jobject object,
600 jbyteArray address) {
601 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
602
603 jbyte* addr = env->GetByteArrayElements(address, NULL);
604 if (!addr) {
605 jniThrowIOException(env, EINVAL);
606 return JNI_FALSE;
607 }
608
609 bt_status_t status = sBluetoothHfpClientInterface->stop_voice_recognition(
610 (const RawAddress*)addr);
611 if (status != BT_STATUS_SUCCESS) {
612 ALOGE("Failed to stop voice recognition, status: %d", status);
613 }
614 env->ReleaseByteArrayElements(address, addr, 0);
615 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
616 }
617
setVolumeNative(JNIEnv * env,jobject object,jbyteArray address,jint volume_type,jint volume)618 static jboolean setVolumeNative(JNIEnv* env, jobject object, jbyteArray address,
619 jint volume_type, jint volume) {
620 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
621
622 jbyte* addr = env->GetByteArrayElements(address, NULL);
623 if (!addr) {
624 jniThrowIOException(env, EINVAL);
625 return JNI_FALSE;
626 }
627
628 bt_status_t status = sBluetoothHfpClientInterface->volume_control(
629 (const RawAddress*)addr, (bthf_client_volume_type_t)volume_type, volume);
630 if (status != BT_STATUS_SUCCESS) {
631 ALOGE("FAILED to control volume, status: %d", status);
632 }
633 env->ReleaseByteArrayElements(address, addr, 0);
634 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
635 }
636
dialNative(JNIEnv * env,jobject object,jbyteArray address,jstring number_str)637 static jboolean dialNative(JNIEnv* env, jobject object, jbyteArray address,
638 jstring number_str) {
639 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
640
641 jbyte* addr = env->GetByteArrayElements(address, NULL);
642 if (!addr) {
643 jniThrowIOException(env, EINVAL);
644 return JNI_FALSE;
645 }
646
647 const char* number = nullptr;
648 if (number_str != nullptr) {
649 number = env->GetStringUTFChars(number_str, nullptr);
650 }
651 bt_status_t status =
652 sBluetoothHfpClientInterface->dial((const RawAddress*)addr,
653 number == nullptr ? "" : number);
654
655 if (status != BT_STATUS_SUCCESS) {
656 ALOGE("Failed to dial, status: %d", status);
657 }
658 if (number != nullptr) {
659 env->ReleaseStringUTFChars(number_str, number);
660 }
661 env->ReleaseByteArrayElements(address, addr, 0);
662 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
663 }
664
dialMemoryNative(JNIEnv * env,jobject object,jbyteArray address,jint location)665 static jboolean dialMemoryNative(JNIEnv* env, jobject object,
666 jbyteArray address, jint location) {
667 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
668
669 jbyte* addr = env->GetByteArrayElements(address, NULL);
670 if (!addr) {
671 jniThrowIOException(env, EINVAL);
672 return JNI_FALSE;
673 }
674
675 bt_status_t status = sBluetoothHfpClientInterface->dial_memory(
676 (const RawAddress*)addr, (int)location);
677 if (status != BT_STATUS_SUCCESS) {
678 ALOGE("Failed to dial from memory, status: %d", status);
679 }
680
681 env->ReleaseByteArrayElements(address, addr, 0);
682 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
683 }
684
handleCallActionNative(JNIEnv * env,jobject object,jbyteArray address,jint action,jint index)685 static jboolean handleCallActionNative(JNIEnv* env, jobject object,
686 jbyteArray address, jint action,
687 jint index) {
688 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
689
690 jbyte* addr = env->GetByteArrayElements(address, NULL);
691 if (!addr) {
692 jniThrowIOException(env, EINVAL);
693 return JNI_FALSE;
694 }
695
696 bt_status_t status = sBluetoothHfpClientInterface->handle_call_action(
697 (const RawAddress*)addr, (bthf_client_call_action_t)action, (int)index);
698
699 if (status != BT_STATUS_SUCCESS) {
700 ALOGE("Failed to enter private mode, status: %d", status);
701 }
702 env->ReleaseByteArrayElements(address, addr, 0);
703 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
704 }
705
queryCurrentCallsNative(JNIEnv * env,jobject object,jbyteArray address)706 static jboolean queryCurrentCallsNative(JNIEnv* env, jobject object,
707 jbyteArray address) {
708 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
709
710 jbyte* addr = env->GetByteArrayElements(address, NULL);
711 if (!addr) {
712 jniThrowIOException(env, EINVAL);
713 return JNI_FALSE;
714 }
715
716 bt_status_t status = sBluetoothHfpClientInterface->query_current_calls(
717 (const RawAddress*)addr);
718
719 if (status != BT_STATUS_SUCCESS) {
720 ALOGE("Failed to query current calls, status: %d", status);
721 }
722 env->ReleaseByteArrayElements(address, addr, 0);
723 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
724 }
725
queryCurrentOperatorNameNative(JNIEnv * env,jobject object,jbyteArray address)726 static jboolean queryCurrentOperatorNameNative(JNIEnv* env, jobject object,
727 jbyteArray address) {
728 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
729
730 jbyte* addr = env->GetByteArrayElements(address, NULL);
731 if (!addr) {
732 jniThrowIOException(env, EINVAL);
733 return JNI_FALSE;
734 }
735
736 bt_status_t status =
737 sBluetoothHfpClientInterface->query_current_operator_name(
738 (const RawAddress*)addr);
739 if (status != BT_STATUS_SUCCESS) {
740 ALOGE("Failed to query current operator name, status: %d", status);
741 }
742
743 env->ReleaseByteArrayElements(address, addr, 0);
744 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
745 }
746
retrieveSubscriberInfoNative(JNIEnv * env,jobject object,jbyteArray address)747 static jboolean retrieveSubscriberInfoNative(JNIEnv* env, jobject object,
748 jbyteArray address) {
749 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
750
751 jbyte* addr = env->GetByteArrayElements(address, NULL);
752 if (!addr) {
753 jniThrowIOException(env, EINVAL);
754 return JNI_FALSE;
755 }
756
757 bt_status_t status = sBluetoothHfpClientInterface->retrieve_subscriber_info(
758 (const RawAddress*)addr);
759 if (status != BT_STATUS_SUCCESS) {
760 ALOGE("Failed to retrieve subscriber info, status: %d", status);
761 }
762
763 env->ReleaseByteArrayElements(address, addr, 0);
764 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
765 }
766
sendDtmfNative(JNIEnv * env,jobject object,jbyteArray address,jbyte code)767 static jboolean sendDtmfNative(JNIEnv* env, jobject object, jbyteArray address,
768 jbyte code) {
769 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
770
771 jbyte* addr = env->GetByteArrayElements(address, NULL);
772 if (!addr) {
773 jniThrowIOException(env, EINVAL);
774 return JNI_FALSE;
775 }
776
777 bt_status_t status = sBluetoothHfpClientInterface->send_dtmf(
778 (const RawAddress*)addr, (char)code);
779 if (status != BT_STATUS_SUCCESS) {
780 ALOGE("Failed to send DTMF, status: %d", status);
781 }
782
783 env->ReleaseByteArrayElements(address, addr, 0);
784 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
785 }
786
requestLastVoiceTagNumberNative(JNIEnv * env,jobject object,jbyteArray address)787 static jboolean requestLastVoiceTagNumberNative(JNIEnv* env, jobject object,
788 jbyteArray address) {
789 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
790
791 jbyte* addr = env->GetByteArrayElements(address, NULL);
792 if (!addr) {
793 jniThrowIOException(env, EINVAL);
794 return JNI_FALSE;
795 }
796
797 bt_status_t status =
798 sBluetoothHfpClientInterface->request_last_voice_tag_number(
799 (const RawAddress*)addr);
800
801 if (status != BT_STATUS_SUCCESS) {
802 ALOGE("Failed to request last Voice Tag number, status: %d", status);
803 }
804
805 env->ReleaseByteArrayElements(address, addr, 0);
806 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
807 }
808
sendATCmdNative(JNIEnv * env,jobject object,jbyteArray address,jint cmd,jint val1,jint val2,jstring arg_str)809 static jboolean sendATCmdNative(JNIEnv* env, jobject object, jbyteArray address,
810 jint cmd, jint val1, jint val2,
811 jstring arg_str) {
812 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
813
814 jbyte* addr = env->GetByteArrayElements(address, NULL);
815 if (!addr) {
816 jniThrowIOException(env, EINVAL);
817 return JNI_FALSE;
818 }
819 const char* arg = NULL;
820 if (arg_str != NULL) {
821 arg = env->GetStringUTFChars(arg_str, NULL);
822 }
823
824 bt_status_t status = sBluetoothHfpClientInterface->send_at_cmd(
825 (const RawAddress*)addr, cmd, val1, val2, arg);
826
827 if (status != BT_STATUS_SUCCESS) {
828 ALOGE("Failed to send cmd, status: %d", status);
829 }
830
831 if (arg != NULL) {
832 env->ReleaseStringUTFChars(arg_str, arg);
833 }
834
835 env->ReleaseByteArrayElements(address, addr, 0);
836 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
837 }
838
839 static JNINativeMethod sMethods[] = {
840 {"classInitNative", "()V", (void*)classInitNative},
841 {"initializeNative", "()V", (void*)initializeNative},
842 {"cleanupNative", "()V", (void*)cleanupNative},
843 {"connectNative", "([B)Z", (void*)connectNative},
844 {"disconnectNative", "([B)Z", (void*)disconnectNative},
845 {"connectAudioNative", "([B)Z", (void*)connectAudioNative},
846 {"disconnectAudioNative", "([B)Z", (void*)disconnectAudioNative},
847 {"startVoiceRecognitionNative", "([B)Z",
848 (void*)startVoiceRecognitionNative},
849 {"stopVoiceRecognitionNative", "([B)Z", (void*)stopVoiceRecognitionNative},
850 {"setVolumeNative", "([BII)Z", (void*)setVolumeNative},
851 {"dialNative", "([BLjava/lang/String;)Z", (void*)dialNative},
852 {"dialMemoryNative", "([BI)Z", (void*)dialMemoryNative},
853 {"handleCallActionNative", "([BII)Z", (void*)handleCallActionNative},
854 {"queryCurrentCallsNative", "([B)Z", (void*)queryCurrentCallsNative},
855 {"queryCurrentOperatorNameNative", "([B)Z",
856 (void*)queryCurrentOperatorNameNative},
857 {"retrieveSubscriberInfoNative", "([B)Z",
858 (void*)retrieveSubscriberInfoNative},
859 {"sendDtmfNative", "([BB)Z", (void*)sendDtmfNative},
860 {"requestLastVoiceTagNumberNative", "([B)Z",
861 (void*)requestLastVoiceTagNumberNative},
862 {"sendATCmdNative", "([BIIILjava/lang/String;)Z", (void*)sendATCmdNative},
863 };
864
register_com_android_bluetooth_hfpclient(JNIEnv * env)865 int register_com_android_bluetooth_hfpclient(JNIEnv* env) {
866 return jniRegisterNativeMethods(
867 env, "com/android/bluetooth/hfpclient/NativeInterface",
868 sMethods, NELEM(sMethods));
869 }
870
871 } /* namespace android */
872