• 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 
348     if ( (btInf = getBluetoothInterface()) == NULL) {
349         ALOGE("Bluetooth module is not loaded");
350         return;
351     }
352 
353     if (sBluetoothHfpClientInterface != NULL) {
354         ALOGW("Cleaning up Bluetooth HFP Client Interface...");
355         sBluetoothHfpClientInterface->cleanup();
356         sBluetoothHfpClientInterface = NULL;
357     }
358 
359     if (mCallbacksObj != NULL) {
360         ALOGW("Cleaning up Bluetooth HFP Client callback object");
361         env->DeleteGlobalRef(mCallbacksObj);
362         mCallbacksObj = NULL;
363     }
364 }
365 
connectNative(JNIEnv * env,jobject object,jbyteArray address)366 static jboolean connectNative(JNIEnv *env, jobject object, jbyteArray address) {
367     jbyte *addr;
368     bt_status_t status;
369 
370     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
371 
372     addr = env->GetByteArrayElements(address, NULL);
373     if (!addr) {
374         jniThrowIOException(env, EINVAL);
375         return JNI_FALSE;
376     }
377 
378     if ((status = sBluetoothHfpClientInterface->connect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
379         ALOGE("Failed AG connection, status: %d", status);
380     }
381     env->ReleaseByteArrayElements(address, addr, 0);
382     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
383 }
384 
disconnectNative(JNIEnv * env,jobject object,jbyteArray address)385 static jboolean disconnectNative(JNIEnv *env, jobject object, jbyteArray address) {
386     jbyte *addr;
387     bt_status_t status;
388 
389     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
390 
391     addr = env->GetByteArrayElements(address, NULL);
392     if (!addr) {
393         jniThrowIOException(env, EINVAL);
394         return JNI_FALSE;
395     }
396 
397     if ( (status = sBluetoothHfpClientInterface->disconnect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
398         ALOGE("Failed AG disconnection, status: %d", status);
399     }
400     env->ReleaseByteArrayElements(address, addr, 0);
401     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
402 }
403 
connectAudioNative(JNIEnv * env,jobject object,jbyteArray address)404 static jboolean connectAudioNative(JNIEnv *env, jobject object, jbyteArray address) {
405     jbyte *addr;
406     bt_status_t status;
407 
408     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
409 
410     addr = env->GetByteArrayElements(address, NULL);
411     if (!addr) {
412         jniThrowIOException(env, EINVAL);
413         return JNI_FALSE;
414     }
415 
416     if ( (status = sBluetoothHfpClientInterface->connect_audio((bt_bdaddr_t *)addr)) !=
417          BT_STATUS_SUCCESS) {
418         ALOGE("Failed AG audio connection, status: %d", status);
419     }
420     env->ReleaseByteArrayElements(address, addr, 0);
421     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
422 }
423 
disconnectAudioNative(JNIEnv * env,jobject object,jbyteArray address)424 static jboolean disconnectAudioNative(JNIEnv *env, jobject object, jbyteArray address) {
425     jbyte *addr;
426     bt_status_t status;
427 
428     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
429 
430     addr = env->GetByteArrayElements(address, NULL);
431     if (!addr) {
432         jniThrowIOException(env, EINVAL);
433         return JNI_FALSE;
434     }
435 
436     if ( (status = sBluetoothHfpClientInterface->disconnect_audio((bt_bdaddr_t *) addr)) !=
437          BT_STATUS_SUCCESS) {
438         ALOGE("Failed AG audio disconnection, status: %d", status);
439     }
440     env->ReleaseByteArrayElements(address, addr, 0);
441     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
442 }
443 
startVoiceRecognitionNative(JNIEnv * env,jobject object)444 static jboolean startVoiceRecognitionNative(JNIEnv *env, jobject object) {
445     bt_status_t status;
446     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
447 
448     if ( (status = sBluetoothHfpClientInterface->start_voice_recognition()) != BT_STATUS_SUCCESS) {
449         ALOGE("Failed to start voice recognition, status: %d", status);
450     }
451     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
452 }
453 
stopVoiceRecognitionNative(JNIEnv * env,jobject object)454 static jboolean stopVoiceRecognitionNative(JNIEnv *env, jobject object) {
455     bt_status_t status;
456     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
457 
458     if ( (status = sBluetoothHfpClientInterface->stop_voice_recognition()) != BT_STATUS_SUCCESS) {
459         ALOGE("Failed to stop voice recognition, status: %d", status);
460     }
461     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
462 }
463 
setVolumeNative(JNIEnv * env,jobject object,jint volume_type,jint volume)464 static jboolean setVolumeNative(JNIEnv *env, jobject object, jint volume_type, jint volume) {
465     bt_status_t status;
466     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
467 
468     if ( (status = sBluetoothHfpClientInterface->volume_control((bthf_client_volume_type_t) volume_type,
469                                                           volume)) != BT_STATUS_SUCCESS) {
470         ALOGE("FAILED to control volume, status: %d", status);
471     }
472     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
473 }
474 
dialNative(JNIEnv * env,jobject object,jstring number_str)475 static jboolean dialNative(JNIEnv *env, jobject object, jstring number_str) {
476     bt_status_t status;
477     const char *number = NULL;
478     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
479 
480     if (number_str != NULL) {
481         number = env->GetStringUTFChars(number_str, NULL);
482     }
483 
484     if ( (status = sBluetoothHfpClientInterface->dial(number)) != BT_STATUS_SUCCESS) {
485         ALOGE("Failed to dial, status: %d", status);
486     }
487     if (number != NULL) {
488         env->ReleaseStringUTFChars(number_str, number);
489     }
490     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
491 }
492 
dialMemoryNative(JNIEnv * env,jobject object,jint location)493 static jboolean dialMemoryNative(JNIEnv *env, jobject object, jint location) {
494     bt_status_t status;
495 
496     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
497 
498     if ( (status = sBluetoothHfpClientInterface->dial_memory((int)location)) != BT_STATUS_SUCCESS) {
499         ALOGE("Failed to dial from memory, status: %d", status);
500     }
501     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
502 }
503 
handleCallActionNative(JNIEnv * env,jobject object,jint action,jint index)504 static jboolean handleCallActionNative(JNIEnv *env, jobject object, jint action, jint index) {
505     bt_status_t status;
506 
507     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
508 
509     if ( (status = sBluetoothHfpClientInterface->handle_call_action((bthf_client_call_action_t)action, (int)index)) != BT_STATUS_SUCCESS) {
510         ALOGE("Failed to enter private mode, status: %d", status);
511     }
512     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
513 }
514 
queryCurrentCallsNative(JNIEnv * env,jobject object)515 static jboolean queryCurrentCallsNative(JNIEnv *env, jobject object) {
516     bt_status_t status;
517 
518     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
519 
520     if ( (status = sBluetoothHfpClientInterface->query_current_calls()) != BT_STATUS_SUCCESS) {
521         ALOGE("Failed to query current calls, status: %d", status);
522     }
523     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
524 }
525 
queryCurrentOperatorNameNative(JNIEnv * env,jobject object)526 static jboolean queryCurrentOperatorNameNative(JNIEnv *env, jobject object) {
527     bt_status_t status;
528 
529     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
530 
531     if ( (status = sBluetoothHfpClientInterface->query_current_operator_name()) != BT_STATUS_SUCCESS) {
532         ALOGE("Failed to query current operator name, status: %d", status);
533     }
534     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
535 }
536 
retrieveSubscriberInfoNative(JNIEnv * env,jobject object)537 static jboolean retrieveSubscriberInfoNative(JNIEnv *env, jobject object) {
538     bt_status_t status;
539 
540     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
541 
542     if ( (status = sBluetoothHfpClientInterface->retrieve_subscriber_info()) != BT_STATUS_SUCCESS) {
543         ALOGE("Failed to retrieve subscriber info, status: %d", status);
544     }
545     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
546 }
547 
sendDtmfNative(JNIEnv * env,jobject object,jbyte code)548 static jboolean sendDtmfNative(JNIEnv *env, jobject object, jbyte code) {
549     bt_status_t status;
550 
551     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
552 
553     if ( (status = sBluetoothHfpClientInterface->send_dtmf((char)code)) != BT_STATUS_SUCCESS) {
554         ALOGE("Failed to send DTMF, status: %d", status);
555     }
556     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
557 }
558 
requestLastVoiceTagNumberNative(JNIEnv * env,jobject object)559 static jboolean requestLastVoiceTagNumberNative(JNIEnv *env, jobject object) {
560     bt_status_t status;
561 
562     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
563 
564     if ( (status = sBluetoothHfpClientInterface->request_last_voice_tag_number()) != BT_STATUS_SUCCESS) {
565         ALOGE("Failed to request last Voice Tag number, status: %d", status);
566     }
567     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
568 }
569 
sendATCmdNative(JNIEnv * env,jobject object,jint cmd,jint val1,jint val2,jstring arg_str)570 static jboolean sendATCmdNative(JNIEnv *env, jobject object, jint cmd,
571                                 jint val1, jint val2, jstring arg_str) {
572     bt_status_t status;
573     const char *arg = NULL;
574 
575     if (!sBluetoothHfpClientInterface) return JNI_FALSE;
576 
577     if (arg_str != NULL) {
578         arg = env->GetStringUTFChars(arg_str, NULL);
579     }
580 
581     if ((status = sBluetoothHfpClientInterface->send_at_cmd(cmd,val1,val2,arg)) !=
582             BT_STATUS_SUCCESS) {
583         ALOGE("Failed to send cmd, status: %d", status);
584     }
585 
586     if (arg != NULL) {
587         env->ReleaseStringUTFChars(arg_str, arg);
588     }
589     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
590 }
591 
592 static JNINativeMethod sMethods[] = {
593     {"classInitNative", "()V", (void *) classInitNative},
594     {"initializeNative", "()V", (void *) initializeNative},
595     {"cleanupNative", "()V", (void *) cleanupNative},
596     {"connectNative", "([B)Z", (void *) connectNative},
597     {"disconnectNative", "([B)Z", (void *) disconnectNative},
598     {"connectAudioNative", "([B)Z", (void *) connectAudioNative},
599     {"disconnectAudioNative", "([B)Z", (void *) disconnectAudioNative},
600     {"startVoiceRecognitionNative", "()Z", (void *) startVoiceRecognitionNative},
601     {"stopVoiceRecognitionNative", "()Z", (void *) stopVoiceRecognitionNative},
602     {"setVolumeNative", "(II)Z", (void *) setVolumeNative},
603     {"dialNative", "(Ljava/lang/String;)Z", (void *) dialNative},
604     {"dialMemoryNative", "(I)Z", (void *) dialMemoryNative},
605     {"handleCallActionNative", "(II)Z", (void *) handleCallActionNative},
606     {"queryCurrentCallsNative", "()Z", (void *) queryCurrentCallsNative},
607     {"queryCurrentOperatorNameNative", "()Z", (void *) queryCurrentOperatorNameNative},
608     {"retrieveSubscriberInfoNative", "()Z", (void *) retrieveSubscriberInfoNative},
609     {"sendDtmfNative", "(B)Z", (void *) sendDtmfNative},
610     {"requestLastVoiceTagNumberNative", "()Z",
611         (void *) requestLastVoiceTagNumberNative},
612     {"sendATCmdNative", "(IIILjava/lang/String;)Z", (void *) sendATCmdNative},
613 };
614 
register_com_android_bluetooth_hfpclient(JNIEnv * env)615 int register_com_android_bluetooth_hfpclient(JNIEnv* env)
616 {
617     return jniRegisterNativeMethods(env, "com/android/bluetooth/hfpclient/HeadsetClientStateMachine",
618                                     sMethods, NELEM(sMethods));
619 }
620 
621 } /* namespace android */
622