• 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 "com_android_bluetooth.h"
22 #include "hardware/bt_hf_client.h"
23 #include "utils/Log.h"
24 #include "android_runtime/AndroidRuntime.h"
25 
26 #define CHECK_CALLBACK_ENV                                                      \
27    if (!checkCallbackThread()) {                                                \
28        ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);\
29        return;                                                                  \
30    }
31 
32 namespace android {
33 
34 static bthf_client_interface_t *sBluetoothHfpClientInterface = NULL;
35 static jobject mCallbacksObj = NULL;
36 static JNIEnv *sCallbackEnv = NULL;
37 
38 static jmethodID method_onConnectionStateChanged;
39 static jmethodID method_onAudioStateChanged;
40 static jmethodID method_onVrStateChanged;
41 static jmethodID method_onNetworkState;
42 static jmethodID method_onNetworkRoaming;
43 static jmethodID method_onNetworkSignal;
44 static jmethodID method_onBatteryLevel;
45 static jmethodID method_onCurrentOperator;
46 static jmethodID method_onCall;
47 static jmethodID method_onCallSetup;
48 static jmethodID method_onCallHeld;
49 static jmethodID method_onRespAndHold;
50 static jmethodID method_onClip;
51 static jmethodID method_onCallWaiting;
52 static jmethodID method_onCurrentCalls;
53 static jmethodID method_onVolumeChange;
54 static jmethodID method_onCmdResult;
55 static jmethodID method_onSubscriberInfo;
56 static jmethodID method_onInBandRing;
57 static jmethodID method_onLastVoiceTagNumber;
58 static jmethodID method_onRingIndication;
59 
checkCallbackThread()60 static bool checkCallbackThread() {
61     // Always fetch the latest callbackEnv from AdapterService.
62     // Caching this could cause this sCallbackEnv to go out-of-sync
63     // with the AdapterService's ENV if an ASSOCIATE/DISASSOCIATE event
64     // is received
65     sCallbackEnv = getCallbackEnv();
66     JNIEnv* env = AndroidRuntime::getJNIEnv();
67     if (sCallbackEnv != env || sCallbackEnv == NULL) return false;
68     return true;
69 }
70 
connection_state_cb(bthf_client_connection_state_t state,unsigned int peer_feat,unsigned int chld_feat,bt_bdaddr_t * bd_addr)71 static void connection_state_cb(bthf_client_connection_state_t state, unsigned int peer_feat, unsigned int chld_feat, bt_bdaddr_t *bd_addr) {
72     jbyteArray addr;
73 
74     CHECK_CALLBACK_ENV
75 
76     addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
77     if (!addr) {
78         ALOGE("Fail to new jbyteArray bd addr for connection state");
79         checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
80         return;
81     }
82 
83     sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
84     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged, (jint) state, (jint) peer_feat, (jint) chld_feat, addr);
85     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
86     sCallbackEnv->DeleteLocalRef(addr);
87 }
88 
audio_state_cb(bthf_client_audio_state_t state,bt_bdaddr_t * bd_addr)89 static void audio_state_cb(bthf_client_audio_state_t state, bt_bdaddr_t *bd_addr) {
90     jbyteArray addr;
91 
92     CHECK_CALLBACK_ENV
93 
94     addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
95     if (!addr) {
96         ALOGE("Fail to new jbyteArray bd addr for audio state");
97         checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
98         return;
99     }
100 
101     sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
102     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioStateChanged, (jint) state, addr);
103     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
104     sCallbackEnv->DeleteLocalRef(addr);
105 }
106 
vr_cmd_cb(bthf_client_vr_state_t state)107 static void vr_cmd_cb(bthf_client_vr_state_t state) {
108     CHECK_CALLBACK_ENV
109     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVrStateChanged, (jint) state);
110     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
111 }
112 
network_state_cb(bthf_client_network_state_t state)113 static void network_state_cb (bthf_client_network_state_t state) {
114     CHECK_CALLBACK_ENV
115     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNetworkState, (jint) state);
116     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
117 }
118 
network_roaming_cb(bthf_client_service_type_t type)119 static void network_roaming_cb (bthf_client_service_type_t type) {
120     CHECK_CALLBACK_ENV
121     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNetworkRoaming, (jint) type);
122     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
123 }
124 
network_signal_cb(int signal)125 static void network_signal_cb (int signal) {
126     CHECK_CALLBACK_ENV
127     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNetworkSignal, (jint) signal);
128     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
129 }
130 
battery_level_cb(int level)131 static void battery_level_cb (int level) {
132     CHECK_CALLBACK_ENV
133     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onBatteryLevel, (jint) level);
134     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
135 }
136 
current_operator_cb(const char * name)137 static void current_operator_cb (const char *name) {
138     jstring js_name;
139 
140     CHECK_CALLBACK_ENV
141 
142     js_name = sCallbackEnv->NewStringUTF(name);
143     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCurrentOperator, js_name);
144     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
145     sCallbackEnv->DeleteLocalRef(js_name);
146 }
147 
call_cb(bthf_client_call_t call)148 static void call_cb (bthf_client_call_t call) {
149     CHECK_CALLBACK_ENV
150     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCall, (jint) call);
151     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
152 }
153 
callsetup_cb(bthf_client_callsetup_t callsetup)154 static void callsetup_cb (bthf_client_callsetup_t callsetup) {
155     CHECK_CALLBACK_ENV
156     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCallSetup, (jint) callsetup);
157     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
158 }
159 
callheld_cb(bthf_client_callheld_t callheld)160 static void callheld_cb (bthf_client_callheld_t callheld) {
161     CHECK_CALLBACK_ENV
162     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCallHeld, (jint) callheld);
163     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
164 }
165 
resp_and_hold_cb(bthf_client_resp_and_hold_t resp_and_hold)166 static void resp_and_hold_cb (bthf_client_resp_and_hold_t resp_and_hold) {
167     CHECK_CALLBACK_ENV
168     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onRespAndHold, (jint) resp_and_hold);
169     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
170 }
171 
clip_cb(const char * number)172 static void clip_cb (const char *number) {
173     jstring js_number;
174 
175     CHECK_CALLBACK_ENV
176 
177     js_number = sCallbackEnv->NewStringUTF(number);
178     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onClip, js_number);
179     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
180     sCallbackEnv->DeleteLocalRef(js_number);
181 }
182 
call_waiting_cb(const char * number)183 static void call_waiting_cb (const char *number) {
184     jstring js_number;
185 
186     CHECK_CALLBACK_ENV
187 
188     js_number = sCallbackEnv->NewStringUTF(number);
189     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCallWaiting, js_number);
190     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
191     sCallbackEnv->DeleteLocalRef(js_number);
192 }
193 
current_calls_cb(int index,bthf_client_call_direction_t dir,bthf_client_call_state_t state,bthf_client_call_mpty_type_t mpty,const char * number)194 static void current_calls_cb (int index, bthf_client_call_direction_t dir,
195                                             bthf_client_call_state_t state,
196                                             bthf_client_call_mpty_type_t mpty,
197                                             const char *number) {
198     jstring js_number;
199 
200     CHECK_CALLBACK_ENV
201 
202     js_number = sCallbackEnv->NewStringUTF(number);
203     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCurrentCalls, index, dir, state, mpty, js_number);
204     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
205     sCallbackEnv->DeleteLocalRef(js_number);
206 }
207 
volume_change_cb(bthf_client_volume_type_t type,int volume)208 static void volume_change_cb (bthf_client_volume_type_t type, int volume) {
209     CHECK_CALLBACK_ENV
210     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVolumeChange, (jint) type, (jint) volume);
211     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
212 }
213 
cmd_complete_cb(bthf_client_cmd_complete_t type,int cme)214 static void cmd_complete_cb (bthf_client_cmd_complete_t type, int cme) {
215     CHECK_CALLBACK_ENV
216     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCmdResult, (jint) type, (jint) cme);
217     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
218 }
219 
subscriber_info_cb(const char * name,bthf_client_subscriber_service_type_t type)220 static void subscriber_info_cb (const char *name, bthf_client_subscriber_service_type_t type) {
221     jstring js_name;
222 
223     CHECK_CALLBACK_ENV
224 
225     js_name = sCallbackEnv->NewStringUTF(name);
226     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onSubscriberInfo, js_name, (jint) type);
227     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
228     sCallbackEnv->DeleteLocalRef(js_name);
229 }
230 
in_band_ring_cb(bthf_client_in_band_ring_state_t in_band)231 static void in_band_ring_cb (bthf_client_in_band_ring_state_t in_band) {
232     CHECK_CALLBACK_ENV
233     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onInBandRing, (jint) in_band);
234     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
235 }
236 
last_voice_tag_number_cb(const char * number)237 static void last_voice_tag_number_cb (const char *number) {
238     jstring js_number;
239 
240     CHECK_CALLBACK_ENV
241 
242     js_number = sCallbackEnv->NewStringUTF(number);
243     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onLastVoiceTagNumber, js_number);
244     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
245     sCallbackEnv->DeleteLocalRef(js_number);
246 }
247 
ring_indication_cb()248 static void ring_indication_cb () {
249     CHECK_CALLBACK_ENV
250     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onRingIndication);
251     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
252 }
253 
254 static bthf_client_callbacks_t sBluetoothHfpClientCallbacks = {
255     sizeof(sBluetoothHfpClientCallbacks),
256     connection_state_cb,
257     audio_state_cb,
258     vr_cmd_cb,
259     network_state_cb,
260     network_roaming_cb,
261     network_signal_cb,
262     battery_level_cb,
263     current_operator_cb,
264     call_cb,
265     callsetup_cb,
266     callheld_cb,
267     resp_and_hold_cb,
268     clip_cb,
269     call_waiting_cb,
270     current_calls_cb,
271     volume_change_cb,
272     cmd_complete_cb,
273     subscriber_info_cb,
274     in_band_ring_cb,
275     last_voice_tag_number_cb,
276     ring_indication_cb,
277 };
278 
classInitNative(JNIEnv * env,jclass clazz)279 static void classInitNative(JNIEnv* env, jclass clazz) {
280     method_onConnectionStateChanged = env->GetMethodID(clazz, "onConnectionStateChanged", "(III[B)V");
281     method_onAudioStateChanged = env->GetMethodID(clazz, "onAudioStateChanged", "(I[B)V");
282     method_onVrStateChanged = env->GetMethodID(clazz, "onVrStateChanged", "(I)V");
283     method_onNetworkState = env->GetMethodID(clazz, "onNetworkState", "(I)V");
284     method_onNetworkRoaming = env->GetMethodID(clazz, "onNetworkRoaming", "(I)V");
285     method_onNetworkSignal = env->GetMethodID(clazz, "onNetworkSignal", "(I)V");
286     method_onBatteryLevel = env->GetMethodID(clazz, "onBatteryLevel", "(I)V");
287     method_onCurrentOperator = env->GetMethodID(clazz, "onCurrentOperator", "(Ljava/lang/String;)V");
288     method_onCall = env->GetMethodID(clazz, "onCall", "(I)V");
289     method_onCallSetup = env->GetMethodID(clazz, "onCallSetup", "(I)V");
290     method_onCallHeld = env->GetMethodID(clazz, "onCallHeld", "(I)V");
291     method_onRespAndHold = env->GetMethodID(clazz, "onRespAndHold", "(I)V");
292     method_onClip = env->GetMethodID(clazz, "onClip", "(Ljava/lang/String;)V");
293     method_onCallWaiting = env->GetMethodID(clazz, "onCallWaiting", "(Ljava/lang/String;)V");
294     method_onCurrentCalls = env->GetMethodID(clazz, "onCurrentCalls", "(IIIILjava/lang/String;)V");
295     method_onVolumeChange = env->GetMethodID(clazz, "onVolumeChange", "(II)V");
296     method_onCmdResult = env->GetMethodID(clazz, "onCmdResult", "(II)V");
297     method_onSubscriberInfo = env->GetMethodID(clazz, "onSubscriberInfo", "(Ljava/lang/String;I)V");
298     method_onInBandRing = env->GetMethodID(clazz, "onInBandRing", "(I)V");
299     method_onLastVoiceTagNumber = env->GetMethodID(clazz, "onLastVoiceTagNumber",
300         "(Ljava/lang/String;)V");
301     method_onRingIndication = env->GetMethodID(clazz, "onRingIndication","()V");
302 
303     ALOGI("%s succeeds", __FUNCTION__);
304 }
305 
initializeNative(JNIEnv * env,jobject object)306 static void initializeNative(JNIEnv *env, jobject object) {
307     const bt_interface_t* btInf;
308     bt_status_t status;
309 
310     btInf = getBluetoothInterface();
311     if (btInf == NULL) {
312         ALOGE("Bluetooth module is not loaded");
313         return;
314     }
315 
316     if (sBluetoothHfpClientInterface != NULL) {
317         ALOGW("Cleaning up Bluetooth HFP Client Interface before initializing");
318         sBluetoothHfpClientInterface->cleanup();
319         sBluetoothHfpClientInterface = NULL;
320     }
321 
322     if (mCallbacksObj != NULL) {
323         ALOGW("Cleaning up Bluetooth HFP Client callback object");
324         env->DeleteGlobalRef(mCallbacksObj);
325         mCallbacksObj = NULL;
326     }
327 
328     sBluetoothHfpClientInterface = (bthf_client_interface_t *)
329             btInf->get_profile_interface(BT_PROFILE_HANDSFREE_CLIENT_ID);
330     if (sBluetoothHfpClientInterface  == NULL) {
331         ALOGE("Failed to get Bluetooth HFP Client Interface");
332         return;
333     }
334 
335     status = sBluetoothHfpClientInterface->init(&sBluetoothHfpClientCallbacks);
336     if (status != BT_STATUS_SUCCESS) {
337         ALOGE("Failed to initialize Bluetooth HFP Client, status: %d", status);
338         sBluetoothHfpClientInterface = NULL;
339         return;
340     }
341 
342     mCallbacksObj = env->NewGlobalRef(object);
343 }
344 
cleanupNative(JNIEnv * env,jobject object)345 static void cleanupNative(JNIEnv *env, jobject object) {
346     const bt_interface_t* btInf;
347     bt_status_t status;
348 
349     if ( (btInf = getBluetoothInterface()) == NULL) {
350         ALOGE("Bluetooth module is not loaded");
351         return;
352     }
353 
354     if (sBluetoothHfpClientInterface != NULL) {
355         ALOGW("Cleaning up Bluetooth HFP Client Interface...");
356         sBluetoothHfpClientInterface->cleanup();
357         sBluetoothHfpClientInterface = NULL;
358     }
359 
360     if (mCallbacksObj != NULL) {
361         ALOGW("Cleaning up Bluetooth HFP Client callback object");
362         env->DeleteGlobalRef(mCallbacksObj);
363         mCallbacksObj = NULL;
364     }
365 }
366 
connectNative(JNIEnv * env,jobject object,jbyteArray address)367 static jboolean connectNative(JNIEnv *env, jobject object, jbyteArray address) {
368     jbyte *addr;
369     bt_status_t status;
370 
371     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
372 
373     addr = env->GetByteArrayElements(address, NULL);
374     if (!addr) {
375         jniThrowIOException(env, EINVAL);
376         return JNI_FALSE;
377     }
378 
379     if ((status = sBluetoothHfpClientInterface->connect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
380         ALOGE("Failed AG connection, status: %d", status);
381     }
382     env->ReleaseByteArrayElements(address, addr, 0);
383     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
384 }
385 
disconnectNative(JNIEnv * env,jobject object,jbyteArray address)386 static jboolean disconnectNative(JNIEnv *env, jobject object, jbyteArray address) {
387     jbyte *addr;
388     bt_status_t status;
389 
390     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
391 
392     addr = env->GetByteArrayElements(address, NULL);
393     if (!addr) {
394         jniThrowIOException(env, EINVAL);
395         return JNI_FALSE;
396     }
397 
398     if ( (status = sBluetoothHfpClientInterface->disconnect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
399         ALOGE("Failed AG disconnection, status: %d", status);
400     }
401     env->ReleaseByteArrayElements(address, addr, 0);
402     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
403 }
404 
connectAudioNative(JNIEnv * env,jobject object,jbyteArray address)405 static jboolean connectAudioNative(JNIEnv *env, jobject object, jbyteArray address) {
406     jbyte *addr;
407     bt_status_t status;
408 
409     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
410 
411     addr = env->GetByteArrayElements(address, NULL);
412     if (!addr) {
413         jniThrowIOException(env, EINVAL);
414         return JNI_FALSE;
415     }
416 
417     if ( (status = sBluetoothHfpClientInterface->connect_audio((bt_bdaddr_t *)addr)) !=
418          BT_STATUS_SUCCESS) {
419         ALOGE("Failed AG audio connection, status: %d", status);
420     }
421     env->ReleaseByteArrayElements(address, addr, 0);
422     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
423 }
424 
disconnectAudioNative(JNIEnv * env,jobject object,jbyteArray address)425 static jboolean disconnectAudioNative(JNIEnv *env, jobject object, jbyteArray address) {
426     jbyte *addr;
427     bt_status_t status;
428 
429     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
430 
431     addr = env->GetByteArrayElements(address, NULL);
432     if (!addr) {
433         jniThrowIOException(env, EINVAL);
434         return JNI_FALSE;
435     }
436 
437     if ( (status = sBluetoothHfpClientInterface->disconnect_audio((bt_bdaddr_t *) addr)) !=
438          BT_STATUS_SUCCESS) {
439         ALOGE("Failed AG audio disconnection, status: %d", status);
440     }
441     env->ReleaseByteArrayElements(address, addr, 0);
442     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
443 }
444 
startVoiceRecognitionNative(JNIEnv * env,jobject object)445 static jboolean startVoiceRecognitionNative(JNIEnv *env, jobject object) {
446     bt_status_t status;
447     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
448 
449     if ( (status = sBluetoothHfpClientInterface->start_voice_recognition()) != BT_STATUS_SUCCESS) {
450         ALOGE("Failed to start voice recognition, status: %d", status);
451     }
452     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
453 }
454 
stopVoiceRecognitionNative(JNIEnv * env,jobject object)455 static jboolean stopVoiceRecognitionNative(JNIEnv *env, jobject object) {
456     bt_status_t status;
457     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
458 
459     if ( (status = sBluetoothHfpClientInterface->stop_voice_recognition()) != BT_STATUS_SUCCESS) {
460         ALOGE("Failed to stop voice recognition, status: %d", status);
461     }
462     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
463 }
464 
setVolumeNative(JNIEnv * env,jobject object,jint volume_type,jint volume)465 static jboolean setVolumeNative(JNIEnv *env, jobject object, jint volume_type, jint volume) {
466     bt_status_t status;
467     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
468 
469     if ( (status = sBluetoothHfpClientInterface->volume_control((bthf_client_volume_type_t) volume_type,
470                                                           volume)) != BT_STATUS_SUCCESS) {
471         ALOGE("FAILED to control volume, status: %d", status);
472     }
473     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
474 }
475 
dialNative(JNIEnv * env,jobject object,jstring number_str)476 static jboolean dialNative(JNIEnv *env, jobject object, jstring number_str) {
477     bt_status_t status;
478     const char *number;
479     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
480 
481     number = env->GetStringUTFChars(number_str, NULL);
482 
483     if ( (status = sBluetoothHfpClientInterface->dial(number)) != BT_STATUS_SUCCESS) {
484         ALOGE("Failed to dial, status: %d", status);
485     }
486     env->ReleaseStringUTFChars(number_str, number);
487     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
488 }
489 
dialMemoryNative(JNIEnv * env,jobject object,jint location)490 static jboolean dialMemoryNative(JNIEnv *env, jobject object, jint location) {
491     bt_status_t status;
492 
493     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
494 
495     if ( (status = sBluetoothHfpClientInterface->dial_memory((int)location)) != BT_STATUS_SUCCESS) {
496         ALOGE("Failed to dial from memory, status: %d", status);
497     }
498     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
499 }
500 
handleCallActionNative(JNIEnv * env,jobject object,jint action,jint index)501 static jboolean handleCallActionNative(JNIEnv *env, jobject object, jint action, jint index) {
502     bt_status_t status;
503 
504     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
505 
506     if ( (status = sBluetoothHfpClientInterface->handle_call_action((bthf_client_call_action_t)action, (int)index)) != BT_STATUS_SUCCESS) {
507         ALOGE("Failed to enter private mode, status: %d", status);
508     }
509     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
510 }
511 
queryCurrentCallsNative(JNIEnv * env,jobject object)512 static jboolean queryCurrentCallsNative(JNIEnv *env, jobject object) {
513     bt_status_t status;
514 
515     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
516 
517     if ( (status = sBluetoothHfpClientInterface->query_current_calls()) != BT_STATUS_SUCCESS) {
518         ALOGE("Failed to query current calls, status: %d", status);
519     }
520     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
521 }
522 
queryCurrentOperatorNameNative(JNIEnv * env,jobject object)523 static jboolean queryCurrentOperatorNameNative(JNIEnv *env, jobject object) {
524     bt_status_t status;
525 
526     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
527 
528     if ( (status = sBluetoothHfpClientInterface->query_current_operator_name()) != BT_STATUS_SUCCESS) {
529         ALOGE("Failed to query current operator name, status: %d", status);
530     }
531     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
532 }
533 
retrieveSubscriberInfoNative(JNIEnv * env,jobject object)534 static jboolean retrieveSubscriberInfoNative(JNIEnv *env, jobject object) {
535     bt_status_t status;
536 
537     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
538 
539     if ( (status = sBluetoothHfpClientInterface->retrieve_subscriber_info()) != BT_STATUS_SUCCESS) {
540         ALOGE("Failed to retrieve subscriber info, status: %d", status);
541     }
542     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
543 }
544 
sendDtmfNative(JNIEnv * env,jobject object,jbyte code)545 static jboolean sendDtmfNative(JNIEnv *env, jobject object, jbyte code) {
546     bt_status_t status;
547 
548     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
549 
550     if ( (status = sBluetoothHfpClientInterface->send_dtmf((char)code)) != BT_STATUS_SUCCESS) {
551         ALOGE("Failed to send DTMF, status: %d", status);
552     }
553     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
554 }
555 
requestLastVoiceTagNumberNative(JNIEnv * env,jobject object)556 static jboolean requestLastVoiceTagNumberNative(JNIEnv *env, jobject object) {
557     bt_status_t status;
558 
559     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
560 
561     if ( (status = sBluetoothHfpClientInterface->request_last_voice_tag_number()) != BT_STATUS_SUCCESS) {
562         ALOGE("Failed to request last Voice Tag number, status: %d", status);
563     }
564     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
565 }
566 
sendATCmdNative(JNIEnv * env,jobject object,jint cmd,jint val1,jint val2,jstring arg_str)567 static jboolean sendATCmdNative(JNIEnv *env, jobject object, jint cmd,
568                                 jint val1, jint val2, jstring arg_str) {
569     bt_status_t status;
570     const char *arg;
571 
572     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
573 
574     arg = env->GetStringUTFChars(arg_str, NULL);
575 
576     if ((status = sBluetoothHfpClientInterface->send_at_cmd(cmd,val1,val2,arg)) !=
577             BT_STATUS_SUCCESS) {
578         ALOGE("Failed to send cmd, status: %d", status);
579     }
580 
581     env->ReleaseStringUTFChars(arg_str, arg);
582     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
583 }
584 
585 static JNINativeMethod sMethods[] = {
586     {"classInitNative", "()V", (void *) classInitNative},
587     {"initializeNative", "()V", (void *) initializeNative},
588     {"cleanupNative", "()V", (void *) cleanupNative},
589     {"connectNative", "([B)Z", (void *) connectNative},
590     {"disconnectNative", "([B)Z", (void *) disconnectNative},
591     {"connectAudioNative", "([B)Z", (void *) connectAudioNative},
592     {"disconnectAudioNative", "([B)Z", (void *) disconnectAudioNative},
593     {"startVoiceRecognitionNative", "()Z", (void *) startVoiceRecognitionNative},
594     {"stopVoiceRecognitionNative", "()Z", (void *) stopVoiceRecognitionNative},
595     {"setVolumeNative", "(II)Z", (void *) setVolumeNative},
596     {"dialNative", "(Ljava/lang/String;)Z", (void *) dialNative},
597     {"dialMemoryNative", "(I)Z", (void *) dialMemoryNative},
598     {"handleCallActionNative", "(II)Z", (void *) handleCallActionNative},
599     {"queryCurrentCallsNative", "()Z", (void *) queryCurrentCallsNative},
600     {"queryCurrentOperatorNameNative", "()Z", (void *) queryCurrentOperatorNameNative},
601     {"retrieveSubscriberInfoNative", "()Z", (void *) retrieveSubscriberInfoNative},
602     {"sendDtmfNative", "(B)Z", (void *) sendDtmfNative},
603     {"requestLastVoiceTagNumberNative", "()Z",
604         (void *) requestLastVoiceTagNumberNative},
605     {"sendATCmdNative", "(IIILjava/lang/String;)Z", (void *) sendATCmdNative},
606 };
607 
register_com_android_bluetooth_hfpclient(JNIEnv * env)608 int register_com_android_bluetooth_hfpclient(JNIEnv* env)
609 {
610     return jniRegisterNativeMethods(env, "com/android/bluetooth/hfpclient/HeadsetClientStateMachine",
611                                     sMethods, NELEM(sMethods));
612 }
613 
614 } /* namespace android */
615