• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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