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
26namespace android {
27
28static bthf_client_interface_t* sBluetoothHfpClientInterface = NULL;
29static jobject mCallbacksObj = NULL;
30
31static jmethodID method_onConnectionStateChanged;
32static jmethodID method_onAudioStateChanged;
33static jmethodID method_onVrStateChanged;
34static jmethodID method_onNetworkState;
35static jmethodID method_onNetworkRoaming;
36static jmethodID method_onNetworkSignal;
37static jmethodID method_onBatteryLevel;
38static jmethodID method_onCurrentOperator;
39static jmethodID method_onCall;
40static jmethodID method_onCallSetup;
41static jmethodID method_onCallHeld;
42static jmethodID method_onRespAndHold;
43static jmethodID method_onClip;
44static jmethodID method_onCallWaiting;
45static jmethodID method_onCurrentCalls;
46static jmethodID method_onVolumeChange;
47static jmethodID method_onCmdResult;
48static jmethodID method_onSubscriberInfo;
49static jmethodID method_onInBandRing;
50static jmethodID method_onLastVoiceTagNumber;
51static jmethodID method_onRingIndication;
52
53static 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
67static 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
83static 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
95static 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
103static 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
115static 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
126static 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
137static 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
148static 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
161static 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
172static 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
188static 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
200static 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
212static 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
225static 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
237static 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
253static 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
264static 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
275static 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
288static 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
299static 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
312static 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
322static 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
347static 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
380static 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
419static 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
439static 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
457static 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
476static 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
495static 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
514static 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
533static 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
552static 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
571static 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
598static 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
618static 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
639static 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
659static 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
680static 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
700static 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
720static 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
742static 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
773static 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
799int 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