blob: 48eee76e6bf8df1429c25f5a87e6fd7b00f4d4ca [file] [log] [blame]
Hemant Guptaaebc7262013-08-19 18:54:29 +05301/*
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
Mike Lockwood8d536f32014-06-12 12:07:01 -070018#define LOG_TAG "BluetoothHeadsetClientServiceJni"
Hemant Guptaaebc7262013-08-19 18:54:29 +053019#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
Hemant Guptaaebc7262013-08-19 18:54:29 +053026namespace android {
27
28static bthf_client_interface_t *sBluetoothHfpClientInterface = NULL;
29static jobject mCallbacksObj = NULL;
Hemant Guptaaebc7262013-08-19 18:54:29 +053030
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
Sanket Agarwalef3a3b52016-11-28 15:53:06 -080053static void connection_state_cb(const bt_bdaddr_t *bd_addr,
54 bthf_client_connection_state_t state,
55 unsigned int peer_feat,
56 unsigned int chld_feat) {
Hemant Guptaaebc7262013-08-19 18:54:29 +053057 jbyteArray addr;
58
Marie Janssenfe377102016-10-11 16:09:58 -070059 CallbackEnv sCallbackEnv(__func__);
60 if (!sCallbackEnv.valid()) return;
Hemant Guptaaebc7262013-08-19 18:54:29 +053061
Sanket Agarwalef3a3b52016-11-28 15:53:06 -080062 addr = sCallbackEnv->NewByteArray(sizeof(const bt_bdaddr_t));
Hemant Guptaaebc7262013-08-19 18:54:29 +053063 if (!addr) {
64 ALOGE("Fail to new jbyteArray bd addr for connection state");
Hemant Guptaaebc7262013-08-19 18:54:29 +053065 return;
66 }
67
Sanket Agarwalef3a3b52016-11-28 15:53:06 -080068 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(const bt_bdaddr_t), (jbyte*) bd_addr);
Hemant Guptaaebc7262013-08-19 18:54:29 +053069 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged, (jint) state, (jint) peer_feat, (jint) chld_feat, addr);
Hemant Guptaaebc7262013-08-19 18:54:29 +053070 sCallbackEnv->DeleteLocalRef(addr);
71}
72
Sanket Agarwalef3a3b52016-11-28 15:53:06 -080073static void audio_state_cb(const bt_bdaddr_t *bd_addr, bthf_client_audio_state_t state) {
Hemant Guptaaebc7262013-08-19 18:54:29 +053074 jbyteArray addr;
75
Marie Janssenfe377102016-10-11 16:09:58 -070076 CallbackEnv sCallbackEnv(__func__);
77 if (!sCallbackEnv.valid()) return;
Hemant Guptaaebc7262013-08-19 18:54:29 +053078
Sanket Agarwalef3a3b52016-11-28 15:53:06 -080079 addr = sCallbackEnv->NewByteArray(sizeof(const bt_bdaddr_t));
Hemant Guptaaebc7262013-08-19 18:54:29 +053080 if (!addr) {
81 ALOGE("Fail to new jbyteArray bd addr for audio state");
Hemant Guptaaebc7262013-08-19 18:54:29 +053082 return;
83 }
84
Sanket Agarwalef3a3b52016-11-28 15:53:06 -080085 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(const bt_bdaddr_t), (jbyte *) bd_addr);
Hemant Guptaaebc7262013-08-19 18:54:29 +053086 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioStateChanged, (jint) state, addr);
Hemant Guptaaebc7262013-08-19 18:54:29 +053087 sCallbackEnv->DeleteLocalRef(addr);
88}
89
Sanket Agarwalef3a3b52016-11-28 15:53:06 -080090static void vr_cmd_cb(const bt_bdaddr_t *bd_addr, bthf_client_vr_state_t state) {
Marie Janssenfe377102016-10-11 16:09:58 -070091 CallbackEnv sCallbackEnv(__func__);
92 if (!sCallbackEnv.valid()) return;
Hemant Guptaaebc7262013-08-19 18:54:29 +053093 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVrStateChanged, (jint) state);
Hemant Guptaaebc7262013-08-19 18:54:29 +053094}
95
Sanket Agarwalef3a3b52016-11-28 15:53:06 -080096static void network_state_cb (const bt_bdaddr_t *bd_addr, bthf_client_network_state_t state) {
Marie Janssenfe377102016-10-11 16:09:58 -070097 CallbackEnv sCallbackEnv(__func__);
98 if (!sCallbackEnv.valid()) return;
Hemant Guptaaebc7262013-08-19 18:54:29 +053099 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNetworkState, (jint) state);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530100}
101
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800102static void network_roaming_cb (const bt_bdaddr_t *bd_addr, bthf_client_service_type_t type) {
Marie Janssenfe377102016-10-11 16:09:58 -0700103 CallbackEnv sCallbackEnv(__func__);
104 if (!sCallbackEnv.valid()) return;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530105 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNetworkRoaming, (jint) type);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530106}
107
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800108static void network_signal_cb (const bt_bdaddr_t *bd_addr, int signal) {
Marie Janssenfe377102016-10-11 16:09:58 -0700109 CallbackEnv sCallbackEnv(__func__);
110 if (!sCallbackEnv.valid()) return;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530111 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNetworkSignal, (jint) signal);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530112}
113
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800114static void battery_level_cb (const bt_bdaddr_t *bd_addr, int level) {
Marie Janssenfe377102016-10-11 16:09:58 -0700115 CallbackEnv sCallbackEnv(__func__);
116 if (!sCallbackEnv.valid()) return;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530117 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onBatteryLevel, (jint) level);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530118}
119
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800120static void current_operator_cb (const bt_bdaddr_t *bd_addr, const char *name) {
Hemant Guptaaebc7262013-08-19 18:54:29 +0530121 jstring js_name;
122
Marie Janssenfe377102016-10-11 16:09:58 -0700123 CallbackEnv sCallbackEnv(__func__);
124 if (!sCallbackEnv.valid()) return;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530125
126 js_name = sCallbackEnv->NewStringUTF(name);
127 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCurrentOperator, js_name);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530128 sCallbackEnv->DeleteLocalRef(js_name);
129}
130
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800131static void call_cb (const bt_bdaddr_t *bd_addr, bthf_client_call_t call) {
Marie Janssenfe377102016-10-11 16:09:58 -0700132 CallbackEnv sCallbackEnv(__func__);
133 if (!sCallbackEnv.valid()) return;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530134 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCall, (jint) call);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530135}
136
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800137static void callsetup_cb (const bt_bdaddr_t *bd_addr,
138 bthf_client_callsetup_t callsetup) {
Marie Janssenfe377102016-10-11 16:09:58 -0700139 CallbackEnv sCallbackEnv(__func__);
140 if (!sCallbackEnv.valid()) return;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530141 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCallSetup, (jint) callsetup);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530142}
143
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800144static void callheld_cb (const bt_bdaddr_t *bd_addr,
145 bthf_client_callheld_t callheld) {
Marie Janssenfe377102016-10-11 16:09:58 -0700146 CallbackEnv sCallbackEnv(__func__);
147 if (!sCallbackEnv.valid()) return;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530148 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCallHeld, (jint) callheld);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530149}
150
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800151static void resp_and_hold_cb (const bt_bdaddr_t *bd_addr,
152 bthf_client_resp_and_hold_t resp_and_hold) {
Marie Janssenfe377102016-10-11 16:09:58 -0700153 CallbackEnv sCallbackEnv(__func__);
154 if (!sCallbackEnv.valid()) return;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530155 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onRespAndHold, (jint) resp_and_hold);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530156}
157
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800158static void clip_cb (const bt_bdaddr_t *bd_addr, const char *number) {
Hemant Guptaaebc7262013-08-19 18:54:29 +0530159 jstring js_number;
160
Marie Janssenfe377102016-10-11 16:09:58 -0700161 CallbackEnv sCallbackEnv(__func__);
162 if (!sCallbackEnv.valid()) return;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530163
164 js_number = sCallbackEnv->NewStringUTF(number);
165 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onClip, js_number);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530166 sCallbackEnv->DeleteLocalRef(js_number);
167}
168
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800169static void call_waiting_cb (const bt_bdaddr_t *bd_addr, const char *number) {
Hemant Guptaaebc7262013-08-19 18:54:29 +0530170 jstring js_number;
171
Marie Janssenfe377102016-10-11 16:09:58 -0700172 CallbackEnv sCallbackEnv(__func__);
173 if (!sCallbackEnv.valid()) return;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530174
175 js_number = sCallbackEnv->NewStringUTF(number);
176 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCallWaiting, js_number);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530177 sCallbackEnv->DeleteLocalRef(js_number);
178}
179
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800180static void current_calls_cb (const bt_bdaddr_t *bd_addr,
181 int index,
182 bthf_client_call_direction_t dir,
183 bthf_client_call_state_t state,
184 bthf_client_call_mpty_type_t mpty,
185 const char *number) {
Hemant Guptaaebc7262013-08-19 18:54:29 +0530186 jstring js_number;
187
Marie Janssenfe377102016-10-11 16:09:58 -0700188 CallbackEnv sCallbackEnv(__func__);
189 if (!sCallbackEnv.valid()) return;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530190
191 js_number = sCallbackEnv->NewStringUTF(number);
192 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCurrentCalls, index, dir, state, mpty, js_number);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530193 sCallbackEnv->DeleteLocalRef(js_number);
194}
195
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800196static void volume_change_cb (const bt_bdaddr_t *bd_addr,
197 bthf_client_volume_type_t type,
198 int volume) {
Marie Janssenfe377102016-10-11 16:09:58 -0700199 CallbackEnv sCallbackEnv(__func__);
200 if (!sCallbackEnv.valid()) return;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530201 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVolumeChange, (jint) type, (jint) volume);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530202}
203
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800204static void cmd_complete_cb (const bt_bdaddr_t *bd_addr,
205 bthf_client_cmd_complete_t type,
206 int cme) {
Marie Janssenfe377102016-10-11 16:09:58 -0700207 CallbackEnv sCallbackEnv(__func__);
208 if (!sCallbackEnv.valid()) return;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530209 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCmdResult, (jint) type, (jint) cme);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530210}
211
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800212static void subscriber_info_cb (const bt_bdaddr_t *bd_addr,
213 const char *name,
214 bthf_client_subscriber_service_type_t type) {
Hemant Guptaaebc7262013-08-19 18:54:29 +0530215 jstring js_name;
216
Marie Janssenfe377102016-10-11 16:09:58 -0700217 CallbackEnv sCallbackEnv(__func__);
218 if (!sCallbackEnv.valid()) return;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530219
220 js_name = sCallbackEnv->NewStringUTF(name);
221 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onSubscriberInfo, js_name, (jint) type);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530222 sCallbackEnv->DeleteLocalRef(js_name);
223}
224
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800225static void in_band_ring_cb (const bt_bdaddr_t *bd_addr,
226 bthf_client_in_band_ring_state_t in_band) {
Marie Janssenfe377102016-10-11 16:09:58 -0700227 CallbackEnv sCallbackEnv(__func__);
228 if (!sCallbackEnv.valid()) return;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530229 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onInBandRing, (jint) in_band);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530230}
231
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800232static void last_voice_tag_number_cb (const bt_bdaddr_t *bd_addr,
233 const char *number) {
Hemant Guptaaebc7262013-08-19 18:54:29 +0530234 jstring js_number;
235
Marie Janssenfe377102016-10-11 16:09:58 -0700236 CallbackEnv sCallbackEnv(__func__);
237 if (!sCallbackEnv.valid()) return;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530238
239 js_number = sCallbackEnv->NewStringUTF(number);
240 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onLastVoiceTagNumber, js_number);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530241 sCallbackEnv->DeleteLocalRef(js_number);
242}
243
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800244static void ring_indication_cb (const bt_bdaddr_t *bd_addr) {
Marie Janssenfe377102016-10-11 16:09:58 -0700245 CallbackEnv sCallbackEnv(__func__);
246 if (!sCallbackEnv.valid()) return;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530247 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onRingIndication);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530248}
249
250static bthf_client_callbacks_t sBluetoothHfpClientCallbacks = {
251 sizeof(sBluetoothHfpClientCallbacks),
252 connection_state_cb,
253 audio_state_cb,
254 vr_cmd_cb,
255 network_state_cb,
256 network_roaming_cb,
257 network_signal_cb,
258 battery_level_cb,
259 current_operator_cb,
260 call_cb,
261 callsetup_cb,
262 callheld_cb,
263 resp_and_hold_cb,
264 clip_cb,
265 call_waiting_cb,
266 current_calls_cb,
267 volume_change_cb,
268 cmd_complete_cb,
269 subscriber_info_cb,
270 in_band_ring_cb,
271 last_voice_tag_number_cb,
272 ring_indication_cb,
273};
274
275static void classInitNative(JNIEnv* env, jclass clazz) {
276 method_onConnectionStateChanged = env->GetMethodID(clazz, "onConnectionStateChanged", "(III[B)V");
277 method_onAudioStateChanged = env->GetMethodID(clazz, "onAudioStateChanged", "(I[B)V");
278 method_onVrStateChanged = env->GetMethodID(clazz, "onVrStateChanged", "(I)V");
279 method_onNetworkState = env->GetMethodID(clazz, "onNetworkState", "(I)V");
280 method_onNetworkRoaming = env->GetMethodID(clazz, "onNetworkRoaming", "(I)V");
281 method_onNetworkSignal = env->GetMethodID(clazz, "onNetworkSignal", "(I)V");
282 method_onBatteryLevel = env->GetMethodID(clazz, "onBatteryLevel", "(I)V");
283 method_onCurrentOperator = env->GetMethodID(clazz, "onCurrentOperator", "(Ljava/lang/String;)V");
284 method_onCall = env->GetMethodID(clazz, "onCall", "(I)V");
285 method_onCallSetup = env->GetMethodID(clazz, "onCallSetup", "(I)V");
286 method_onCallHeld = env->GetMethodID(clazz, "onCallHeld", "(I)V");
287 method_onRespAndHold = env->GetMethodID(clazz, "onRespAndHold", "(I)V");
288 method_onClip = env->GetMethodID(clazz, "onClip", "(Ljava/lang/String;)V");
289 method_onCallWaiting = env->GetMethodID(clazz, "onCallWaiting", "(Ljava/lang/String;)V");
290 method_onCurrentCalls = env->GetMethodID(clazz, "onCurrentCalls", "(IIIILjava/lang/String;)V");
291 method_onVolumeChange = env->GetMethodID(clazz, "onVolumeChange", "(II)V");
292 method_onCmdResult = env->GetMethodID(clazz, "onCmdResult", "(II)V");
293 method_onSubscriberInfo = env->GetMethodID(clazz, "onSubscriberInfo", "(Ljava/lang/String;I)V");
294 method_onInBandRing = env->GetMethodID(clazz, "onInBandRing", "(I)V");
295 method_onLastVoiceTagNumber = env->GetMethodID(clazz, "onLastVoiceTagNumber",
296 "(Ljava/lang/String;)V");
297 method_onRingIndication = env->GetMethodID(clazz, "onRingIndication","()V");
298
299 ALOGI("%s succeeds", __FUNCTION__);
300}
301
302static void initializeNative(JNIEnv *env, jobject object) {
303 const bt_interface_t* btInf;
304 bt_status_t status;
305
306 btInf = getBluetoothInterface();
307 if (btInf == NULL) {
308 ALOGE("Bluetooth module is not loaded");
309 return;
310 }
311
312 if (sBluetoothHfpClientInterface != NULL) {
313 ALOGW("Cleaning up Bluetooth HFP Client Interface before initializing");
314 sBluetoothHfpClientInterface->cleanup();
315 sBluetoothHfpClientInterface = NULL;
316 }
317
318 if (mCallbacksObj != NULL) {
319 ALOGW("Cleaning up Bluetooth HFP Client callback object");
320 env->DeleteGlobalRef(mCallbacksObj);
321 mCallbacksObj = NULL;
322 }
323
324 sBluetoothHfpClientInterface = (bthf_client_interface_t *)
325 btInf->get_profile_interface(BT_PROFILE_HANDSFREE_CLIENT_ID);
326 if (sBluetoothHfpClientInterface == NULL) {
327 ALOGE("Failed to get Bluetooth HFP Client Interface");
328 return;
329 }
330
331 status = sBluetoothHfpClientInterface->init(&sBluetoothHfpClientCallbacks);
332 if (status != BT_STATUS_SUCCESS) {
333 ALOGE("Failed to initialize Bluetooth HFP Client, status: %d", status);
334 sBluetoothHfpClientInterface = NULL;
335 return;
336 }
337
338 mCallbacksObj = env->NewGlobalRef(object);
339}
340
341static void cleanupNative(JNIEnv *env, jobject object) {
342 const bt_interface_t* btInf;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530343
344 if ( (btInf = getBluetoothInterface()) == NULL) {
345 ALOGE("Bluetooth module is not loaded");
346 return;
347 }
348
349 if (sBluetoothHfpClientInterface != NULL) {
350 ALOGW("Cleaning up Bluetooth HFP Client Interface...");
351 sBluetoothHfpClientInterface->cleanup();
352 sBluetoothHfpClientInterface = NULL;
353 }
354
355 if (mCallbacksObj != NULL) {
356 ALOGW("Cleaning up Bluetooth HFP Client callback object");
357 env->DeleteGlobalRef(mCallbacksObj);
358 mCallbacksObj = NULL;
359 }
360}
361
362static jboolean connectNative(JNIEnv *env, jobject object, jbyteArray address) {
363 jbyte *addr;
364 bt_status_t status;
365
366 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
367
368 addr = env->GetByteArrayElements(address, NULL);
369 if (!addr) {
370 jniThrowIOException(env, EINVAL);
371 return JNI_FALSE;
372 }
373
374 if ((status = sBluetoothHfpClientInterface->connect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
375 ALOGE("Failed AG connection, status: %d", status);
376 }
377 env->ReleaseByteArrayElements(address, addr, 0);
378 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
379}
380
381static jboolean disconnectNative(JNIEnv *env, jobject object, jbyteArray address) {
382 jbyte *addr;
383 bt_status_t status;
384
385 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
386
387 addr = env->GetByteArrayElements(address, NULL);
388 if (!addr) {
389 jniThrowIOException(env, EINVAL);
390 return JNI_FALSE;
391 }
392
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800393 if ( (status = sBluetoothHfpClientInterface->disconnect((const bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
Hemant Guptaaebc7262013-08-19 18:54:29 +0530394 ALOGE("Failed AG disconnection, status: %d", status);
395 }
396 env->ReleaseByteArrayElements(address, addr, 0);
397 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
398}
399
400static jboolean connectAudioNative(JNIEnv *env, jobject object, jbyteArray address) {
401 jbyte *addr;
402 bt_status_t status;
403
404 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
405
406 addr = env->GetByteArrayElements(address, NULL);
407 if (!addr) {
408 jniThrowIOException(env, EINVAL);
409 return JNI_FALSE;
410 }
411
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800412 if ( (status = sBluetoothHfpClientInterface->connect_audio((const bt_bdaddr_t *)addr)) !=
Hemant Guptaaebc7262013-08-19 18:54:29 +0530413 BT_STATUS_SUCCESS) {
414 ALOGE("Failed AG audio connection, status: %d", status);
415 }
416 env->ReleaseByteArrayElements(address, addr, 0);
417 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
418}
419
420static jboolean disconnectAudioNative(JNIEnv *env, jobject object, jbyteArray address) {
421 jbyte *addr;
422 bt_status_t status;
423
424 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
425
426 addr = env->GetByteArrayElements(address, NULL);
427 if (!addr) {
428 jniThrowIOException(env, EINVAL);
429 return JNI_FALSE;
430 }
431
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800432 if ( (status = sBluetoothHfpClientInterface->disconnect_audio((const bt_bdaddr_t *) addr)) !=
Hemant Guptaaebc7262013-08-19 18:54:29 +0530433 BT_STATUS_SUCCESS) {
434 ALOGE("Failed AG audio disconnection, status: %d", status);
435 }
436 env->ReleaseByteArrayElements(address, addr, 0);
437 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
438}
439
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800440static jboolean startVoiceRecognitionNative(JNIEnv *env, jobject object, jbyteArray address) {
441 jbyte *addr;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530442 bt_status_t status;
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800443
Hemant Guptaaebc7262013-08-19 18:54:29 +0530444 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
445
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800446 addr = env->GetByteArrayElements(address, NULL);
447 if (!addr) {
448 jniThrowIOException(env, EINVAL);
449 return JNI_FALSE;
450 }
451
452 if ( (status = sBluetoothHfpClientInterface->start_voice_recognition(
453 (const bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
Hemant Guptaaebc7262013-08-19 18:54:29 +0530454 ALOGE("Failed to start voice recognition, status: %d", status);
455 }
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800456 env->ReleaseByteArrayElements(address, addr, 0);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530457 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
458}
459
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800460static jboolean stopVoiceRecognitionNative(JNIEnv *env, jobject object, jbyteArray address) {
461 jbyte *addr;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530462 bt_status_t status;
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800463
Hemant Guptaaebc7262013-08-19 18:54:29 +0530464 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
465
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800466 addr = env->GetByteArrayElements(address, NULL);
467 if (!addr) {
468 jniThrowIOException(env, EINVAL);
469 return JNI_FALSE;
470 }
471
472 if ( (status = sBluetoothHfpClientInterface->stop_voice_recognition(
473 (const bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
Hemant Guptaaebc7262013-08-19 18:54:29 +0530474 ALOGE("Failed to stop voice recognition, status: %d", status);
475 }
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800476 env->ReleaseByteArrayElements(address, addr, 0);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530477 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
478}
479
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800480static jboolean setVolumeNative(
481 JNIEnv *env, jobject object, jbyteArray address, jint volume_type, jint volume) {
482
483 jbyte *addr;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530484 bt_status_t status;
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800485
Hemant Guptaaebc7262013-08-19 18:54:29 +0530486 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
487
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800488 addr = env->GetByteArrayElements(address, NULL);
489 if (!addr) {
490 jniThrowIOException(env, EINVAL);
491 return JNI_FALSE;
492 }
493
494 if ( (status = sBluetoothHfpClientInterface->volume_control(
495 (const bt_bdaddr_t *)addr, (bthf_client_volume_type_t) volume_type, volume)) != BT_STATUS_SUCCESS) {
Hemant Guptaaebc7262013-08-19 18:54:29 +0530496 ALOGE("FAILED to control volume, status: %d", status);
497 }
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800498 env->ReleaseByteArrayElements(address, addr, 0);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530499 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
500}
501
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800502static jboolean dialNative(JNIEnv *env, jobject object, jbyteArray address, jstring number_str) {
503 jbyte *addr;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530504 bt_status_t status;
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800505
David Stevens613dd4f2015-04-15 12:05:14 -0700506 const char *number = NULL;
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800507
Hemant Guptaaebc7262013-08-19 18:54:29 +0530508 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
509
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800510 addr = env->GetByteArrayElements(address, NULL);
511 if (!addr) {
512 jniThrowIOException(env, EINVAL);
513 return JNI_FALSE;
514 }
515
David Stevens613dd4f2015-04-15 12:05:14 -0700516 if (number_str != NULL) {
517 number = env->GetStringUTFChars(number_str, NULL);
518 }
Hemant Guptaaebc7262013-08-19 18:54:29 +0530519
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800520 if ( (status = sBluetoothHfpClientInterface->dial(
521 (const bt_bdaddr_t *)addr, number)) != BT_STATUS_SUCCESS) {
Hemant Guptaaebc7262013-08-19 18:54:29 +0530522 ALOGE("Failed to dial, status: %d", status);
523 }
David Stevens613dd4f2015-04-15 12:05:14 -0700524 if (number != NULL) {
525 env->ReleaseStringUTFChars(number_str, number);
526 }
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800527 env->ReleaseByteArrayElements(address, addr, 0);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530528 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
529}
530
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800531static jboolean dialMemoryNative(JNIEnv *env, jobject object, jbyteArray address, jint location) {
532 jbyte *addr;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530533 bt_status_t status;
534
535 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
536
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800537 addr = env->GetByteArrayElements(address, NULL);
538 if (!addr) {
539 jniThrowIOException(env, EINVAL);
540 return JNI_FALSE;
541 }
542
543 status = sBluetoothHfpClientInterface->dial_memory(
544 (const bt_bdaddr_t *) addr,
545 (int) location);
546
547 if (status != BT_STATUS_SUCCESS) {
Hemant Guptaaebc7262013-08-19 18:54:29 +0530548 ALOGE("Failed to dial from memory, status: %d", status);
549 }
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800550
551 env->ReleaseByteArrayElements(address, addr, 0);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530552 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
553}
554
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800555static jboolean handleCallActionNative(
556 JNIEnv *env, jobject object, jbyteArray address, jint action, jint index) {
557 jbyte *addr;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530558 bt_status_t status;
559
560 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
561
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800562 addr = env->GetByteArrayElements(address, NULL);
563 if (!addr) {
564 jniThrowIOException(env, EINVAL);
565 return JNI_FALSE;
566 }
567
568 status = sBluetoothHfpClientInterface->handle_call_action(
569 (const bt_bdaddr_t *) addr,
570 (bthf_client_call_action_t) action,
571 (int) index);
572
573 if (status != BT_STATUS_SUCCESS) {
Hemant Guptaaebc7262013-08-19 18:54:29 +0530574 ALOGE("Failed to enter private mode, status: %d", status);
575 }
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800576
577 env->ReleaseByteArrayElements(address, addr, 0);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530578 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
579}
580
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800581static jboolean queryCurrentCallsNative(JNIEnv *env, jobject object, jbyteArray address) {
582 jbyte *addr;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530583 bt_status_t status;
584
585 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
586
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800587 addr = env->GetByteArrayElements(address, NULL);
588 if (!addr) {
589 jniThrowIOException(env, EINVAL);
590 return JNI_FALSE;
591 }
592
593 status = sBluetoothHfpClientInterface->query_current_calls((const bt_bdaddr_t *) addr);
594
595 if (status != BT_STATUS_SUCCESS) {
Hemant Guptaaebc7262013-08-19 18:54:29 +0530596 ALOGE("Failed to query current calls, status: %d", status);
597 }
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800598 env->ReleaseByteArrayElements(address, addr, 0);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530599 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
600}
601
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800602static jboolean queryCurrentOperatorNameNative(JNIEnv *env, jobject object, jbyteArray address) {
603 jbyte *addr;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530604 bt_status_t status;
605
606 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
607
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800608 addr = env->GetByteArrayElements(address, NULL);
609 if (!addr) {
610 jniThrowIOException(env, EINVAL);
611 return JNI_FALSE;
612 }
613
614 status = sBluetoothHfpClientInterface->query_current_operator_name((const bt_bdaddr_t *) addr);
615 if (status != BT_STATUS_SUCCESS) {
Hemant Guptaaebc7262013-08-19 18:54:29 +0530616 ALOGE("Failed to query current operator name, status: %d", status);
617 }
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800618
619 env->ReleaseByteArrayElements(address, addr, 0);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530620 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
621}
622
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800623static jboolean retrieveSubscriberInfoNative(JNIEnv *env, jobject object, jbyteArray address) {
624 jbyte *addr;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530625 bt_status_t status;
626
627 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
628
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800629 addr = env->GetByteArrayElements(address, NULL);
630 if (!addr) {
631 jniThrowIOException(env, EINVAL);
632 return JNI_FALSE;
633 }
634
635 status = sBluetoothHfpClientInterface->retrieve_subscriber_info((const bt_bdaddr_t *) addr);
636
637 if (status != BT_STATUS_SUCCESS) {
Hemant Guptaaebc7262013-08-19 18:54:29 +0530638 ALOGE("Failed to retrieve subscriber info, status: %d", status);
639 }
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800640
641 env->ReleaseByteArrayElements(address, addr, 0);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530642 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
643}
644
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800645static jboolean sendDtmfNative(JNIEnv *env, jobject object, jbyte code, jbyteArray address) {
646 jbyte *addr;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530647 bt_status_t status;
648
649 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
650
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800651 addr = env->GetByteArrayElements(address, NULL);
652 if (!addr) {
653 jniThrowIOException(env, EINVAL);
654 return JNI_FALSE;
655 }
656
657 status = sBluetoothHfpClientInterface->send_dtmf(
658 (const bt_bdaddr_t *) addr,
659 (char) code);
660
661 if (status != BT_STATUS_SUCCESS) {
Hemant Guptaaebc7262013-08-19 18:54:29 +0530662 ALOGE("Failed to send DTMF, status: %d", status);
663 }
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800664
665 env->ReleaseByteArrayElements(address, addr, 0);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530666 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
667}
668
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800669static jboolean requestLastVoiceTagNumberNative(JNIEnv *env, jobject object, jbyteArray address) {
670 jbyte *addr;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530671 bt_status_t status;
672
673 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
674
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800675 addr = env->GetByteArrayElements(address, NULL);
676 if (!addr) {
677 jniThrowIOException(env, EINVAL);
678 return JNI_FALSE;
679 }
680
681 status = sBluetoothHfpClientInterface->request_last_voice_tag_number(
682 (const bt_bdaddr_t *)addr);
683
684 if (status != BT_STATUS_SUCCESS) {
Hemant Guptaaebc7262013-08-19 18:54:29 +0530685 ALOGE("Failed to request last Voice Tag number, status: %d", status);
686 }
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800687
688 env->ReleaseByteArrayElements(address, addr, 0);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530689 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
690}
691
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800692static jboolean sendATCmdNative(JNIEnv *env, jobject object, jbyteArray address, jint cmd,
Hemant Guptaaebc7262013-08-19 18:54:29 +0530693 jint val1, jint val2, jstring arg_str) {
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800694 jbyte *addr;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530695 bt_status_t status;
Rakesh Iyerd96a7fa2015-04-08 12:27:53 -0700696 const char *arg = NULL;
Hemant Guptaaebc7262013-08-19 18:54:29 +0530697
698 if (!sBluetoothHfpClientInterface) return JNI_FALSE;
699
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800700 addr = env->GetByteArrayElements(address, NULL);
701 if (!addr) {
702 jniThrowIOException(env, EINVAL);
703 return JNI_FALSE;
704 }
705
Rakesh Iyerd96a7fa2015-04-08 12:27:53 -0700706 if (arg_str != NULL) {
707 arg = env->GetStringUTFChars(arg_str, NULL);
708 }
Hemant Guptaaebc7262013-08-19 18:54:29 +0530709
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800710 status = sBluetoothHfpClientInterface->send_at_cmd(
711 (const bt_bdaddr_t *) addr, cmd, val1, val2, arg);
712
713 if (status != BT_STATUS_SUCCESS) {
Hemant Guptaaebc7262013-08-19 18:54:29 +0530714 ALOGE("Failed to send cmd, status: %d", status);
715 }
716
Rakesh Iyerd96a7fa2015-04-08 12:27:53 -0700717 if (arg != NULL) {
718 env->ReleaseStringUTFChars(arg_str, arg);
719 }
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800720
721 env->ReleaseByteArrayElements(address, addr, 0);
Hemant Guptaaebc7262013-08-19 18:54:29 +0530722 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
723}
724
725static JNINativeMethod sMethods[] = {
726 {"classInitNative", "()V", (void *) classInitNative},
727 {"initializeNative", "()V", (void *) initializeNative},
728 {"cleanupNative", "()V", (void *) cleanupNative},
729 {"connectNative", "([B)Z", (void *) connectNative},
730 {"disconnectNative", "([B)Z", (void *) disconnectNative},
731 {"connectAudioNative", "([B)Z", (void *) connectAudioNative},
732 {"disconnectAudioNative", "([B)Z", (void *) disconnectAudioNative},
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800733 {"startVoiceRecognitionNative", "([B)Z", (void *) startVoiceRecognitionNative},
734 {"stopVoiceRecognitionNative", "([B)Z", (void *) stopVoiceRecognitionNative},
735 {"setVolumeNative", "([BII)Z", (void *) setVolumeNative},
736 {"dialNative", "([BLjava/lang/String;)Z", (void *) dialNative},
737 {"dialMemoryNative", "([BI)Z", (void *) dialMemoryNative},
738 {"handleCallActionNative", "([BII)Z", (void *) handleCallActionNative},
739 {"queryCurrentCallsNative", "([B)Z", (void *) queryCurrentCallsNative},
740 {"queryCurrentOperatorNameNative", "([B)Z", (void *) queryCurrentOperatorNameNative},
741 {"retrieveSubscriberInfoNative", "([B)Z", (void *) retrieveSubscriberInfoNative},
742 {"sendDtmfNative", "([BB)Z", (void *) sendDtmfNative},
743 {"requestLastVoiceTagNumberNative", "([B)Z",
Hemant Guptaaebc7262013-08-19 18:54:29 +0530744 (void *) requestLastVoiceTagNumberNative},
Sanket Agarwalef3a3b52016-11-28 15:53:06 -0800745 {"sendATCmdNative", "([BIIILjava/lang/String;)Z", (void *) sendATCmdNative},
Hemant Guptaaebc7262013-08-19 18:54:29 +0530746};
747
748int register_com_android_bluetooth_hfpclient(JNIEnv* env)
749{
Mike Lockwood8d536f32014-06-12 12:07:01 -0700750 return jniRegisterNativeMethods(env, "com/android/bluetooth/hfpclient/HeadsetClientStateMachine",
Hemant Guptaaebc7262013-08-19 18:54:29 +0530751 sMethods, NELEM(sMethods));
752}
753
754} /* namespace android */