• 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 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