1 /*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "BluetoothHidServiceJni"
18
19 #define LOG_NDEBUG 1
20
21 #define CHECK_CALLBACK_ENV \
22 if (!checkCallbackThread()) { \
23 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);\
24 return; \
25 }
26
27 #include "com_android_bluetooth.h"
28 #include "hardware/bt_hh.h"
29 #include "utils/Log.h"
30 #include "android_runtime/AndroidRuntime.h"
31
32 #include <string.h>
33
34 namespace android {
35
36 static jmethodID method_onConnectStateChanged;
37 static jmethodID method_onGetProtocolMode;
38 static jmethodID method_onGetReport;
39 static jmethodID method_onHandshake;
40 static jmethodID method_onVirtualUnplug;
41
42 static const bthh_interface_t *sBluetoothHidInterface = NULL;
43 static jobject mCallbacksObj = NULL;
44 static JNIEnv *sCallbackEnv = NULL;
45
checkCallbackThread()46 static bool checkCallbackThread() {
47
48 // Always fetch the latest callbackEnv from AdapterService.
49 // Caching this could cause this sCallbackEnv to go out-of-sync
50 // with the AdapterService's ENV if an ASSOCIATE/DISASSOCIATE event
51 // is received
52
53 sCallbackEnv = getCallbackEnv();
54
55 JNIEnv* env = AndroidRuntime::getJNIEnv();
56 if (sCallbackEnv != env || sCallbackEnv == NULL) return false;
57 return true;
58 }
59
connection_state_callback(bt_bdaddr_t * bd_addr,bthh_connection_state_t state)60 static void connection_state_callback(bt_bdaddr_t *bd_addr, bthh_connection_state_t state) {
61 jbyteArray addr;
62
63 CHECK_CALLBACK_ENV
64 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
65 if (!addr) {
66 ALOGE("Fail to new jbyteArray bd addr for HID channel state");
67 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
68 return;
69 }
70 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
71
72 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectStateChanged, addr, (jint) state);
73 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
74 sCallbackEnv->DeleteLocalRef(addr);
75 }
76
get_protocol_mode_callback(bt_bdaddr_t * bd_addr,bthh_status_t hh_status,bthh_protocol_mode_t mode)77 static void get_protocol_mode_callback(bt_bdaddr_t *bd_addr, bthh_status_t hh_status,bthh_protocol_mode_t mode) {
78 jbyteArray addr;
79
80 CHECK_CALLBACK_ENV
81 if (hh_status != BTHH_OK) {
82 ALOGE("BTHH Status is not OK!");
83 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
84 return;
85 }
86
87 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
88 if (!addr) {
89 ALOGE("Fail to new jbyteArray bd addr for get protocal mode callback");
90 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
91 return;
92 }
93 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
94
95 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetProtocolMode, addr, (jint) mode);
96 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
97 sCallbackEnv->DeleteLocalRef(addr);
98 }
99
get_report_callback(bt_bdaddr_t * bd_addr,bthh_status_t hh_status,uint8_t * rpt_data,int rpt_size)100 static void get_report_callback(bt_bdaddr_t *bd_addr, bthh_status_t hh_status, uint8_t *rpt_data, int rpt_size) {
101 jbyteArray addr;
102 jbyteArray data;
103
104 CHECK_CALLBACK_ENV
105 if (hh_status != BTHH_OK) {
106 ALOGE("BTHH Status is not OK!");
107 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
108 return;
109 }
110
111 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
112 if (!addr) {
113 ALOGE("Fail to new jbyteArray bd addr for get report callback");
114 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
115 return;
116 }
117 data = sCallbackEnv->NewByteArray(rpt_size);
118 if (!data) {
119 ALOGE("Fail to new jbyteArray data for get report callback");
120 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
121 sCallbackEnv->DeleteLocalRef(addr);
122 return;
123 }
124
125 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
126 sCallbackEnv->SetByteArrayRegion(data, 0, rpt_size, (jbyte *) rpt_data);
127
128 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetReport, addr, data, (jint) rpt_size);
129 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
130 sCallbackEnv->DeleteLocalRef(addr);
131 sCallbackEnv->DeleteLocalRef(data);
132 }
133
virtual_unplug_callback(bt_bdaddr_t * bd_addr,bthh_status_t hh_status)134 static void virtual_unplug_callback(bt_bdaddr_t *bd_addr, bthh_status_t hh_status) {
135 ALOGV("call to virtual_unplug_callback");
136 jbyteArray addr;
137
138 CHECK_CALLBACK_ENV
139 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
140 if (!addr) {
141 ALOGE("Fail to new jbyteArray bd addr for HID channel state");
142 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
143 return;
144 }
145 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
146
147 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVirtualUnplug, addr, (jint) hh_status);
148 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
149 sCallbackEnv->DeleteLocalRef(addr);
150
151 /*jbyteArray addr;
152 jint status = hh_status;
153 CHECK_CALLBACK_ENV
154 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
155 if (!addr) {
156 ALOGE("Fail to new jbyteArray bd addr for HID report");
157 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
158 return;
159 }
160 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
161
162 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVirtualUnplug, addr, status);
163 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
164 sCallbackEnv->DeleteLocalRef(addr);*/
165 }
166
handshake_callback(bt_bdaddr_t * bd_addr,bthh_status_t hh_status)167 static void handshake_callback(bt_bdaddr_t *bd_addr, bthh_status_t hh_status)
168 {
169 jbyteArray addr;
170
171 CHECK_CALLBACK_ENV
172
173 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
174 if (!addr) {
175 ALOGE("Fail to new jbyteArray bd addr for handshake callback");
176 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
177 return;
178 }
179 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
180 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onHandshake, addr, (jint) hh_status);
181 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
182 sCallbackEnv->DeleteLocalRef(addr);
183 }
184
185 static bthh_callbacks_t sBluetoothHidCallbacks = {
186 sizeof(sBluetoothHidCallbacks),
187 connection_state_callback,
188 NULL,
189 get_protocol_mode_callback,
190 NULL,
191 get_report_callback,
192 virtual_unplug_callback,
193 handshake_callback
194 };
195
196 // Define native functions
197
classInitNative(JNIEnv * env,jclass clazz)198 static void classInitNative(JNIEnv* env, jclass clazz) {
199 int err;
200 // const bt_interface_t* btInf;
201 // bt_status_t status;
202
203 method_onConnectStateChanged = env->GetMethodID(clazz, "onConnectStateChanged", "([BI)V");
204 method_onGetProtocolMode = env->GetMethodID(clazz, "onGetProtocolMode", "([BI)V");
205 method_onGetReport = env->GetMethodID(clazz, "onGetReport", "([B[BI)V");
206 method_onHandshake = env->GetMethodID(clazz, "onHandshake", "([BI)V");
207 method_onVirtualUnplug = env->GetMethodID(clazz, "onVirtualUnplug", "([BI)V");
208
209 /*
210 if ( (btInf = getBluetoothInterface()) == NULL) {
211 ALOGE("Bluetooth module is not loaded");
212 return;
213 }
214
215 if ( (sBluetoothHidInterface = (bthh_interface_t *)
216 btInf->get_profile_interface(BT_PROFILE_HIDHOST_ID)) == NULL) {
217 ALOGE("Failed to get Bluetooth Handsfree Interface");
218 return;
219 }
220
221 // TODO(BT) do this only once or
222 // Do we need to do this every time the BT reenables?
223 if ( (status = sBluetoothHidInterface->init(&sBluetoothHidCallbacks)) != BT_STATUS_SUCCESS) {
224 ALOGE("Failed to initialize Bluetooth HID, status: %d", status);
225 sBluetoothHidInterface = NULL;
226 return;
227 }
228
229 */
230 ALOGI("%s: succeeds", __FUNCTION__);
231 }
232
initializeNative(JNIEnv * env,jobject object)233 static void initializeNative(JNIEnv *env, jobject object) {
234 const bt_interface_t* btInf;
235 bt_status_t status;
236
237 if ( (btInf = getBluetoothInterface()) == NULL) {
238 ALOGE("Bluetooth module is not loaded");
239 return;
240 }
241
242 if (sBluetoothHidInterface !=NULL) {
243 ALOGW("Cleaning up Bluetooth HID Interface before initializing...");
244 sBluetoothHidInterface->cleanup();
245 sBluetoothHidInterface = NULL;
246 }
247
248 if (mCallbacksObj != NULL) {
249 ALOGW("Cleaning up Bluetooth GID callback object");
250 env->DeleteGlobalRef(mCallbacksObj);
251 mCallbacksObj = NULL;
252 }
253
254
255 if ( (sBluetoothHidInterface = (bthh_interface_t *)
256 btInf->get_profile_interface(BT_PROFILE_HIDHOST_ID)) == NULL) {
257 ALOGE("Failed to get Bluetooth HID Interface");
258 return;
259 }
260
261 if ( (status = sBluetoothHidInterface->init(&sBluetoothHidCallbacks)) != BT_STATUS_SUCCESS) {
262 ALOGE("Failed to initialize Bluetooth HID, status: %d", status);
263 sBluetoothHidInterface = NULL;
264 return;
265 }
266
267
268
269 mCallbacksObj = env->NewGlobalRef(object);
270 }
271
cleanupNative(JNIEnv * env,jobject object)272 static void cleanupNative(JNIEnv *env, jobject object) {
273 const bt_interface_t* btInf;
274 bt_status_t status;
275
276 if ( (btInf = getBluetoothInterface()) == NULL) {
277 ALOGE("Bluetooth module is not loaded");
278 return;
279 }
280
281 if (sBluetoothHidInterface !=NULL) {
282 ALOGW("Cleaning up Bluetooth HID Interface...");
283 sBluetoothHidInterface->cleanup();
284 sBluetoothHidInterface = NULL;
285 }
286
287 if (mCallbacksObj != NULL) {
288 ALOGW("Cleaning up Bluetooth GID callback object");
289 env->DeleteGlobalRef(mCallbacksObj);
290 mCallbacksObj = NULL;
291 }
292
293 env->DeleteGlobalRef(mCallbacksObj);
294 }
295
connectHidNative(JNIEnv * env,jobject object,jbyteArray address)296 static jboolean connectHidNative(JNIEnv *env, jobject object, jbyteArray address) {
297 bt_status_t status;
298 jbyte *addr;
299 jboolean ret = JNI_TRUE;
300 if (!sBluetoothHidInterface) return JNI_FALSE;
301
302 addr = env->GetByteArrayElements(address, NULL);
303 if (!addr) {
304 ALOGE("Bluetooth device address null");
305 return JNI_FALSE;
306 }
307
308 if ((status = sBluetoothHidInterface->connect((bt_bdaddr_t *) addr)) !=
309 BT_STATUS_SUCCESS) {
310 ALOGE("Failed HID channel connection, status: %d", status);
311 ret = JNI_FALSE;
312 }
313 env->ReleaseByteArrayElements(address, addr, 0);
314
315 return ret;
316 }
317
disconnectHidNative(JNIEnv * env,jobject object,jbyteArray address)318 static jboolean disconnectHidNative(JNIEnv *env, jobject object, jbyteArray address) {
319 bt_status_t status;
320 jbyte *addr;
321 jboolean ret = JNI_TRUE;
322 if (!sBluetoothHidInterface) return JNI_FALSE;
323
324 addr = env->GetByteArrayElements(address, NULL);
325 if (!addr) {
326 ALOGE("Bluetooth device address null");
327 return JNI_FALSE;
328 }
329
330 if ( (status = sBluetoothHidInterface->disconnect((bt_bdaddr_t *) addr)) !=
331 BT_STATUS_SUCCESS) {
332 ALOGE("Failed disconnect hid channel, status: %d", status);
333 ret = JNI_FALSE;
334 }
335 env->ReleaseByteArrayElements(address, addr, 0);
336
337 return ret;
338 }
339
getProtocolModeNative(JNIEnv * env,jobject object,jbyteArray address)340 static jboolean getProtocolModeNative(JNIEnv *env, jobject object, jbyteArray address) {
341 bt_status_t status;
342 jbyte *addr;
343 jboolean ret = JNI_TRUE;
344 bthh_protocol_mode_t protocolMode;
345 if (!sBluetoothHidInterface) return JNI_FALSE;
346
347 addr = env->GetByteArrayElements(address, NULL);
348 if (!addr) {
349 ALOGE("Bluetooth device address null");
350 return JNI_FALSE;
351 }
352
353 if ( (status = sBluetoothHidInterface->get_protocol((bt_bdaddr_t *) addr, (bthh_protocol_mode_t) protocolMode)) !=
354 BT_STATUS_SUCCESS) {
355 ALOGE("Failed get protocol mode, status: %d", status);
356 ret = JNI_FALSE;
357 }
358 env->ReleaseByteArrayElements(address, addr, 0);
359
360 return ret;
361 }
362
virtualUnPlugNative(JNIEnv * env,jobject object,jbyteArray address)363 static jboolean virtualUnPlugNative(JNIEnv *env, jobject object, jbyteArray address) {
364 bt_status_t status;
365 jbyte *addr;
366 jboolean ret = JNI_TRUE;
367 if (!sBluetoothHidInterface) return JNI_FALSE;
368
369 addr = env->GetByteArrayElements(address, NULL);
370 if (!addr) {
371 ALOGE("Bluetooth device address null");
372 return JNI_FALSE;
373 }
374 if ( (status = sBluetoothHidInterface->virtual_unplug((bt_bdaddr_t *) addr)) !=
375 BT_STATUS_SUCCESS) {
376 ALOGE("Failed virual unplug, status: %d", status);
377 ret = JNI_FALSE;
378 }
379 env->ReleaseByteArrayElements(address, addr, 0);
380 return ret;
381
382 }
383
384
setProtocolModeNative(JNIEnv * env,jobject object,jbyteArray address,jint protocolMode)385 static jboolean setProtocolModeNative(JNIEnv *env, jobject object, jbyteArray address, jint protocolMode) {
386 bt_status_t status;
387 jbyte *addr;
388 jboolean ret = JNI_TRUE;
389 if (!sBluetoothHidInterface) return JNI_FALSE;
390
391 ALOGD("%s: protocolMode = %d", __FUNCTION__, protocolMode);
392
393 addr = env->GetByteArrayElements(address, NULL);
394 if (!addr) {
395 ALOGE("Bluetooth device address null");
396 return JNI_FALSE;
397 }
398
399 bthh_protocol_mode_t mode;
400 switch(protocolMode){
401 case 0:
402 mode = BTHH_REPORT_MODE;
403 break;
404 case 1:
405 mode = BTHH_BOOT_MODE;
406 break;
407 default:
408 ALOGE("Unknown HID protocol mode");
409 return JNI_FALSE;
410 }
411 if ( (status = sBluetoothHidInterface->set_protocol((bt_bdaddr_t *) addr, mode)) !=
412 BT_STATUS_SUCCESS) {
413 ALOGE("Failed set protocol mode, status: %d", status);
414 ret = JNI_FALSE;
415 }
416 env->ReleaseByteArrayElements(address, addr, 0);
417
418 return JNI_TRUE;
419 }
420
getReportNative(JNIEnv * env,jobject object,jbyteArray address,jbyte reportType,jbyte reportId,jint bufferSize)421 static jboolean getReportNative(JNIEnv *env, jobject object, jbyteArray address, jbyte reportType, jbyte reportId, jint bufferSize) {
422 ALOGV("%s: reportType = %d, reportId = %d, bufferSize = %d", __FUNCTION__, reportType, reportId, bufferSize);
423
424 bt_status_t status;
425 jbyte *addr;
426 jboolean ret = JNI_TRUE;
427 if (!sBluetoothHidInterface) return JNI_FALSE;
428
429 addr = env->GetByteArrayElements(address, NULL);
430 if (!addr) {
431 ALOGE("Bluetooth device address null");
432 return JNI_FALSE;
433 }
434
435 jint rType = reportType;
436 jint rId = reportId;
437
438 if ( (status = sBluetoothHidInterface->get_report((bt_bdaddr_t *) addr, (bthh_report_type_t) rType, (uint8_t) rId, bufferSize)) !=
439 BT_STATUS_SUCCESS) {
440 ALOGE("Failed get report, status: %d", status);
441 ret = JNI_FALSE;
442 }
443 env->ReleaseByteArrayElements(address, addr, 0);
444
445 return ret;
446 }
447
448
setReportNative(JNIEnv * env,jobject object,jbyteArray address,jbyte reportType,jstring report)449 static jboolean setReportNative(JNIEnv *env, jobject object, jbyteArray address, jbyte reportType, jstring report) {
450 ALOGV("%s: reportType = %d", __FUNCTION__, reportType);
451 bt_status_t status;
452 jbyte *addr;
453 jboolean ret = JNI_TRUE;
454 if (!sBluetoothHidInterface) return JNI_FALSE;
455
456 addr = env->GetByteArrayElements(address, NULL);
457 if (!addr) {
458 ALOGE("Bluetooth device address null");
459 return JNI_FALSE;
460 }
461 jint rType = reportType;
462 const char *c_report = env->GetStringUTFChars(report, NULL);
463
464 if ( (status = sBluetoothHidInterface->set_report((bt_bdaddr_t *) addr, (bthh_report_type_t)rType, (char*) c_report)) !=
465 BT_STATUS_SUCCESS) {
466 ALOGE("Failed set report, status: %d", status);
467 ret = JNI_FALSE;
468 }
469 env->ReleaseStringUTFChars(report, c_report);
470 env->ReleaseByteArrayElements(address, addr, 0);
471
472 return ret;
473 }
474
sendDataNative(JNIEnv * env,jobject object,jbyteArray address,jstring report)475 static jboolean sendDataNative(JNIEnv *env, jobject object, jbyteArray address, jstring report) {
476 ALOGV("%s", __FUNCTION__);
477 bt_status_t status;
478 jbyte *addr;
479 jboolean ret = JNI_TRUE;
480 if (!sBluetoothHidInterface) return JNI_FALSE;
481
482 addr = env->GetByteArrayElements(address, NULL);
483 if (!addr) {
484 ALOGE("Bluetooth device address null");
485 return JNI_FALSE;
486 }
487 const char *c_report = env->GetStringUTFChars(report, NULL);
488 if ( (status = sBluetoothHidInterface->send_data((bt_bdaddr_t *) addr, (char*) c_report)) !=
489 BT_STATUS_SUCCESS) {
490 ALOGE("Failed set report, status: %d", status);
491 ret = JNI_FALSE;
492 }
493 env->ReleaseStringUTFChars(report, c_report);
494 env->ReleaseByteArrayElements(address, addr, 0);
495
496 return ret;
497
498 }
499
500 static JNINativeMethod sMethods[] = {
501 {"classInitNative", "()V", (void *) classInitNative},
502 {"initializeNative", "()V", (void *) initializeNative},
503 {"cleanupNative", "()V", (void *) cleanupNative},
504 {"connectHidNative", "([B)Z", (void *) connectHidNative},
505 {"disconnectHidNative", "([B)Z", (void *) disconnectHidNative},
506 {"getProtocolModeNative", "([B)Z", (void *) getProtocolModeNative},
507 {"virtualUnPlugNative", "([B)Z", (void *) virtualUnPlugNative},
508 {"setProtocolModeNative", "([BB)Z", (void *) setProtocolModeNative},
509 {"getReportNative", "([BBBI)Z", (void *) getReportNative},
510 {"setReportNative", "([BBLjava/lang/String;)Z", (void *) setReportNative},
511 {"sendDataNative", "([BLjava/lang/String;)Z", (void *) sendDataNative},
512 };
513
register_com_android_bluetooth_hid(JNIEnv * env)514 int register_com_android_bluetooth_hid(JNIEnv* env)
515 {
516 return jniRegisterNativeMethods(env, "com/android/bluetooth/hid/HidService",
517 sMethods, NELEM(sMethods));
518 }
519
520 }
521