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 method_onConnectStateChanged = env->GetMethodID(clazz, "onConnectStateChanged", "([BI)V");
200 method_onGetProtocolMode = env->GetMethodID(clazz, "onGetProtocolMode", "([BI)V");
201 method_onGetReport = env->GetMethodID(clazz, "onGetReport", "([B[BI)V");
202 method_onHandshake = env->GetMethodID(clazz, "onHandshake", "([BI)V");
203 method_onVirtualUnplug = env->GetMethodID(clazz, "onVirtualUnplug", "([BI)V");
204
205 ALOGI("%s: succeeds", __FUNCTION__);
206 }
207
initializeNative(JNIEnv * env,jobject object)208 static void initializeNative(JNIEnv *env, jobject object) {
209 const bt_interface_t* btInf;
210 bt_status_t status;
211
212 if ( (btInf = getBluetoothInterface()) == NULL) {
213 ALOGE("Bluetooth module is not loaded");
214 return;
215 }
216
217 if (sBluetoothHidInterface !=NULL) {
218 ALOGW("Cleaning up Bluetooth HID Interface before initializing...");
219 sBluetoothHidInterface->cleanup();
220 sBluetoothHidInterface = NULL;
221 }
222
223 if (mCallbacksObj != NULL) {
224 ALOGW("Cleaning up Bluetooth GID callback object");
225 env->DeleteGlobalRef(mCallbacksObj);
226 mCallbacksObj = NULL;
227 }
228
229
230 if ( (sBluetoothHidInterface = (bthh_interface_t *)
231 btInf->get_profile_interface(BT_PROFILE_HIDHOST_ID)) == NULL) {
232 ALOGE("Failed to get Bluetooth HID Interface");
233 return;
234 }
235
236 if ( (status = sBluetoothHidInterface->init(&sBluetoothHidCallbacks)) != BT_STATUS_SUCCESS) {
237 ALOGE("Failed to initialize Bluetooth HID, status: %d", status);
238 sBluetoothHidInterface = NULL;
239 return;
240 }
241
242
243
244 mCallbacksObj = env->NewGlobalRef(object);
245 }
246
cleanupNative(JNIEnv * env,jobject object)247 static void cleanupNative(JNIEnv *env, jobject object) {
248 const bt_interface_t* btInf;
249
250 if ( (btInf = getBluetoothInterface()) == NULL) {
251 ALOGE("Bluetooth module is not loaded");
252 return;
253 }
254
255 if (sBluetoothHidInterface !=NULL) {
256 ALOGW("Cleaning up Bluetooth HID Interface...");
257 sBluetoothHidInterface->cleanup();
258 sBluetoothHidInterface = NULL;
259 }
260
261 if (mCallbacksObj != NULL) {
262 ALOGW("Cleaning up Bluetooth GID callback object");
263 env->DeleteGlobalRef(mCallbacksObj);
264 mCallbacksObj = NULL;
265 }
266
267 env->DeleteGlobalRef(mCallbacksObj);
268 }
269
connectHidNative(JNIEnv * env,jobject object,jbyteArray address)270 static jboolean connectHidNative(JNIEnv *env, jobject object, jbyteArray address) {
271 bt_status_t status;
272 jbyte *addr;
273 jboolean ret = JNI_TRUE;
274 if (!sBluetoothHidInterface) return JNI_FALSE;
275
276 addr = env->GetByteArrayElements(address, NULL);
277 if (!addr) {
278 ALOGE("Bluetooth device address null");
279 return JNI_FALSE;
280 }
281
282 if ((status = sBluetoothHidInterface->connect((bt_bdaddr_t *) addr)) !=
283 BT_STATUS_SUCCESS) {
284 ALOGE("Failed HID channel connection, status: %d", status);
285 ret = JNI_FALSE;
286 }
287 env->ReleaseByteArrayElements(address, addr, 0);
288
289 return ret;
290 }
291
disconnectHidNative(JNIEnv * env,jobject object,jbyteArray address)292 static jboolean disconnectHidNative(JNIEnv *env, jobject object, jbyteArray address) {
293 bt_status_t status;
294 jbyte *addr;
295 jboolean ret = JNI_TRUE;
296 if (!sBluetoothHidInterface) return JNI_FALSE;
297
298 addr = env->GetByteArrayElements(address, NULL);
299 if (!addr) {
300 ALOGE("Bluetooth device address null");
301 return JNI_FALSE;
302 }
303
304 if ( (status = sBluetoothHidInterface->disconnect((bt_bdaddr_t *) addr)) !=
305 BT_STATUS_SUCCESS) {
306 ALOGE("Failed disconnect hid channel, status: %d", status);
307 ret = JNI_FALSE;
308 }
309 env->ReleaseByteArrayElements(address, addr, 0);
310
311 return ret;
312 }
313
getProtocolModeNative(JNIEnv * env,jobject object,jbyteArray address)314 static jboolean getProtocolModeNative(JNIEnv *env, jobject object, jbyteArray address) {
315 bt_status_t status;
316 jbyte *addr;
317 jboolean ret = JNI_TRUE;
318 bthh_protocol_mode_t protocolMode;
319 if (!sBluetoothHidInterface) return JNI_FALSE;
320
321 addr = env->GetByteArrayElements(address, NULL);
322 if (!addr) {
323 ALOGE("Bluetooth device address null");
324 return JNI_FALSE;
325 }
326
327 if ( (status = sBluetoothHidInterface->get_protocol((bt_bdaddr_t *) addr, (bthh_protocol_mode_t) protocolMode)) !=
328 BT_STATUS_SUCCESS) {
329 ALOGE("Failed get protocol mode, status: %d", status);
330 ret = JNI_FALSE;
331 }
332 env->ReleaseByteArrayElements(address, addr, 0);
333
334 return ret;
335 }
336
virtualUnPlugNative(JNIEnv * env,jobject object,jbyteArray address)337 static jboolean virtualUnPlugNative(JNIEnv *env, jobject object, jbyteArray address) {
338 bt_status_t status;
339 jbyte *addr;
340 jboolean ret = JNI_TRUE;
341 if (!sBluetoothHidInterface) return JNI_FALSE;
342
343 addr = env->GetByteArrayElements(address, NULL);
344 if (!addr) {
345 ALOGE("Bluetooth device address null");
346 return JNI_FALSE;
347 }
348 if ( (status = sBluetoothHidInterface->virtual_unplug((bt_bdaddr_t *) addr)) !=
349 BT_STATUS_SUCCESS) {
350 ALOGE("Failed virual unplug, status: %d", status);
351 ret = JNI_FALSE;
352 }
353 env->ReleaseByteArrayElements(address, addr, 0);
354 return ret;
355
356 }
357
358
setProtocolModeNative(JNIEnv * env,jobject object,jbyteArray address,jint protocolMode)359 static jboolean setProtocolModeNative(JNIEnv *env, jobject object, jbyteArray address, jint protocolMode) {
360 bt_status_t status;
361 jbyte *addr;
362 jboolean ret = JNI_TRUE;
363 if (!sBluetoothHidInterface) return JNI_FALSE;
364
365 ALOGD("%s: protocolMode = %d", __FUNCTION__, protocolMode);
366
367 addr = env->GetByteArrayElements(address, NULL);
368 if (!addr) {
369 ALOGE("Bluetooth device address null");
370 return JNI_FALSE;
371 }
372
373 bthh_protocol_mode_t mode;
374 switch(protocolMode){
375 case 0:
376 mode = BTHH_REPORT_MODE;
377 break;
378 case 1:
379 mode = BTHH_BOOT_MODE;
380 break;
381 default:
382 ALOGE("Unknown HID protocol mode");
383 return JNI_FALSE;
384 }
385 if ( (status = sBluetoothHidInterface->set_protocol((bt_bdaddr_t *) addr, mode)) !=
386 BT_STATUS_SUCCESS) {
387 ALOGE("Failed set protocol mode, status: %d", status);
388 ret = JNI_FALSE;
389 }
390 env->ReleaseByteArrayElements(address, addr, 0);
391
392 return JNI_TRUE;
393 }
394
getReportNative(JNIEnv * env,jobject object,jbyteArray address,jbyte reportType,jbyte reportId,jint bufferSize)395 static jboolean getReportNative(JNIEnv *env, jobject object, jbyteArray address, jbyte reportType, jbyte reportId, jint bufferSize) {
396 ALOGV("%s: reportType = %d, reportId = %d, bufferSize = %d", __FUNCTION__, reportType, reportId, bufferSize);
397
398 bt_status_t status;
399 jbyte *addr;
400 jboolean ret = JNI_TRUE;
401 if (!sBluetoothHidInterface) return JNI_FALSE;
402
403 addr = env->GetByteArrayElements(address, NULL);
404 if (!addr) {
405 ALOGE("Bluetooth device address null");
406 return JNI_FALSE;
407 }
408
409 jint rType = reportType;
410 jint rId = reportId;
411
412 if ( (status = sBluetoothHidInterface->get_report((bt_bdaddr_t *) addr, (bthh_report_type_t) rType, (uint8_t) rId, bufferSize)) !=
413 BT_STATUS_SUCCESS) {
414 ALOGE("Failed get report, status: %d", status);
415 ret = JNI_FALSE;
416 }
417 env->ReleaseByteArrayElements(address, addr, 0);
418
419 return ret;
420 }
421
422
setReportNative(JNIEnv * env,jobject object,jbyteArray address,jbyte reportType,jstring report)423 static jboolean setReportNative(JNIEnv *env, jobject object, jbyteArray address, jbyte reportType, jstring report) {
424 ALOGV("%s: reportType = %d", __FUNCTION__, reportType);
425 bt_status_t status;
426 jbyte *addr;
427 jboolean ret = JNI_TRUE;
428 if (!sBluetoothHidInterface) return JNI_FALSE;
429
430 addr = env->GetByteArrayElements(address, NULL);
431 if (!addr) {
432 ALOGE("Bluetooth device address null");
433 return JNI_FALSE;
434 }
435 jint rType = reportType;
436 const char *c_report = env->GetStringUTFChars(report, NULL);
437
438 if ( (status = sBluetoothHidInterface->set_report((bt_bdaddr_t *) addr, (bthh_report_type_t)rType, (char*) c_report)) !=
439 BT_STATUS_SUCCESS) {
440 ALOGE("Failed set report, status: %d", status);
441 ret = JNI_FALSE;
442 }
443 env->ReleaseStringUTFChars(report, c_report);
444 env->ReleaseByteArrayElements(address, addr, 0);
445
446 return ret;
447 }
448
sendDataNative(JNIEnv * env,jobject object,jbyteArray address,jstring report)449 static jboolean sendDataNative(JNIEnv *env, jobject object, jbyteArray address, jstring report) {
450 ALOGV("%s", __FUNCTION__);
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 const char *c_report = env->GetStringUTFChars(report, NULL);
462 if ( (status = sBluetoothHidInterface->send_data((bt_bdaddr_t *) addr, (char*) c_report)) !=
463 BT_STATUS_SUCCESS) {
464 ALOGE("Failed set report, status: %d", status);
465 ret = JNI_FALSE;
466 }
467 env->ReleaseStringUTFChars(report, c_report);
468 env->ReleaseByteArrayElements(address, addr, 0);
469
470 return ret;
471
472 }
473
474 static JNINativeMethod sMethods[] = {
475 {"classInitNative", "()V", (void *) classInitNative},
476 {"initializeNative", "()V", (void *) initializeNative},
477 {"cleanupNative", "()V", (void *) cleanupNative},
478 {"connectHidNative", "([B)Z", (void *) connectHidNative},
479 {"disconnectHidNative", "([B)Z", (void *) disconnectHidNative},
480 {"getProtocolModeNative", "([B)Z", (void *) getProtocolModeNative},
481 {"virtualUnPlugNative", "([B)Z", (void *) virtualUnPlugNative},
482 {"setProtocolModeNative", "([BB)Z", (void *) setProtocolModeNative},
483 {"getReportNative", "([BBBI)Z", (void *) getReportNative},
484 {"setReportNative", "([BBLjava/lang/String;)Z", (void *) setReportNative},
485 {"sendDataNative", "([BLjava/lang/String;)Z", (void *) sendDataNative},
486 };
487
register_com_android_bluetooth_hid(JNIEnv * env)488 int register_com_android_bluetooth_hid(JNIEnv* env)
489 {
490 return jniRegisterNativeMethods(env, "com/android/bluetooth/hid/HidService",
491 sMethods, NELEM(sMethods));
492 }
493
494 }
495