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