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