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 "BluetoothHidHostServiceJni"
18
19 #include "com_android_bluetooth.h"
20 #include "hardware/bt_hh.h"
21 #include "utils/Log.h"
22
23 #include <string.h>
24 #include <shared_mutex>
25 namespace android {
26
27 static jmethodID method_onConnectStateChanged;
28 static jmethodID method_onGetProtocolMode;
29 static jmethodID method_onGetReport;
30 static jmethodID method_onHandshake;
31 static jmethodID method_onVirtualUnplug;
32 static jmethodID method_onGetIdleTime;
33
34 static const bthh_interface_t* sBluetoothHidInterface = NULL;
35 static jobject mCallbacksObj = NULL;
36 static std::shared_timed_mutex mCallbacks_mutex;
37
marshall_bda(RawAddress * bd_addr)38 static jbyteArray marshall_bda(RawAddress* bd_addr) {
39 CallbackEnv sCallbackEnv(__func__);
40 if (!sCallbackEnv.valid()) return NULL;
41
42 jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(RawAddress));
43 if (!addr) {
44 log::error("Fail to new jbyteArray bd addr");
45 return NULL;
46 }
47 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(RawAddress),
48 (jbyte*)bd_addr);
49 return addr;
50 }
51
connection_state_callback(RawAddress * bd_addr,tBLE_ADDR_TYPE addr_type,tBT_TRANSPORT transport,bthh_connection_state_t state)52 static void connection_state_callback(RawAddress* bd_addr,
53 tBLE_ADDR_TYPE addr_type,
54 tBT_TRANSPORT transport,
55 bthh_connection_state_t state) {
56 std::shared_lock<std::shared_timed_mutex> lock(mCallbacks_mutex);
57 CallbackEnv sCallbackEnv(__func__);
58 if (!sCallbackEnv.valid()) return;
59 if (!mCallbacksObj) {
60 log::error("mCallbacksObj is null");
61 return;
62 }
63 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
64 if (!addr.get()) {
65 log::error("Fail to new jbyteArray bd addr for HID channel state");
66 return;
67 }
68
69 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectStateChanged,
70 addr.get(), (jint)addr_type, (jint)transport,
71 (jint)state);
72 }
73
get_protocol_mode_callback(RawAddress * bd_addr,tBLE_ADDR_TYPE addr_type,tBT_TRANSPORT transport,bthh_status_t hh_status,bthh_protocol_mode_t mode)74 static void get_protocol_mode_callback(RawAddress* bd_addr,
75 tBLE_ADDR_TYPE addr_type,
76 tBT_TRANSPORT transport,
77 bthh_status_t hh_status,
78 bthh_protocol_mode_t mode) {
79 std::shared_lock<std::shared_timed_mutex> lock(mCallbacks_mutex);
80 CallbackEnv sCallbackEnv(__func__);
81 if (!sCallbackEnv.valid()) return;
82 if (!mCallbacksObj) {
83 log::error("mCallbacksObj is null");
84 return;
85 }
86 if (hh_status != BTHH_OK) {
87 log::error("BTHH Status is not OK!");
88 return;
89 }
90
91 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
92 if (!addr.get()) {
93 log::error("Fail to new jbyteArray bd addr for get protocol mode callback");
94 return;
95 }
96
97 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetProtocolMode,
98 addr.get(), (jint)addr_type, (jint)transport,
99 (jint)mode);
100 }
101
get_report_callback(RawAddress * bd_addr,tBLE_ADDR_TYPE addr_type,tBT_TRANSPORT transport,bthh_status_t hh_status,uint8_t * rpt_data,int rpt_size)102 static void get_report_callback(RawAddress* bd_addr, tBLE_ADDR_TYPE addr_type,
103 tBT_TRANSPORT transport,
104 bthh_status_t hh_status, uint8_t* rpt_data,
105 int rpt_size) {
106 std::shared_lock<std::shared_timed_mutex> lock(mCallbacks_mutex);
107 CallbackEnv sCallbackEnv(__func__);
108 if (!sCallbackEnv.valid()) return;
109 if (!mCallbacksObj) {
110 log::error("mCallbacksObj is null");
111 return;
112 }
113 if (hh_status != BTHH_OK) {
114 log::error("BTHH Status is not OK!");
115 return;
116 }
117
118 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
119 if (!addr.get()) {
120 log::error("Fail to new jbyteArray bd addr for get report callback");
121 return;
122 }
123 ScopedLocalRef<jbyteArray> data(sCallbackEnv.get(),
124 sCallbackEnv->NewByteArray(rpt_size));
125 if (!data.get()) {
126 log::error("Fail to new jbyteArray data for get report callback");
127 return;
128 }
129
130 sCallbackEnv->SetByteArrayRegion(data.get(), 0, rpt_size, (jbyte*)rpt_data);
131 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetReport, addr.get(),
132 (jint)addr_type, (jint)transport, data.get(),
133 (jint)rpt_size);
134 }
135
virtual_unplug_callback(RawAddress * bd_addr,tBLE_ADDR_TYPE addr_type,tBT_TRANSPORT transport,bthh_status_t hh_status)136 static void virtual_unplug_callback(RawAddress* bd_addr,
137 tBLE_ADDR_TYPE addr_type,
138 tBT_TRANSPORT transport,
139 bthh_status_t hh_status) {
140 log::verbose("call to virtual_unplug_callback");
141 std::shared_lock<std::shared_timed_mutex> lock(mCallbacks_mutex);
142 CallbackEnv sCallbackEnv(__func__);
143 if (!sCallbackEnv.valid()) return;
144 if (!mCallbacksObj) {
145 log::error("mCallbacksObj is null");
146 return;
147 }
148 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
149 if (!addr.get()) {
150 log::error("Fail to new jbyteArray bd addr for HID channel state");
151 return;
152 }
153 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVirtualUnplug,
154 addr.get(), (jint)addr_type, (jint)transport,
155 (jint)hh_status);
156 }
157
handshake_callback(RawAddress * bd_addr,tBLE_ADDR_TYPE addr_type,tBT_TRANSPORT transport,bthh_status_t hh_status)158 static void handshake_callback(RawAddress* bd_addr, tBLE_ADDR_TYPE addr_type,
159 tBT_TRANSPORT transport,
160 bthh_status_t hh_status) {
161 std::shared_lock<std::shared_timed_mutex> lock(mCallbacks_mutex);
162 CallbackEnv sCallbackEnv(__func__);
163 if (!sCallbackEnv.valid()) return;
164 if (!mCallbacksObj) {
165 log::error("mCallbacksObj is null");
166 return;
167 }
168
169 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
170 if (!addr.get()) {
171 log::error("Fail to new jbyteArray bd addr for handshake callback");
172 return;
173 }
174 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onHandshake, addr.get(),
175 (jint)addr_type, (jint)transport,
176 (jint)hh_status);
177 }
178
get_idle_time_callback(RawAddress * bd_addr,tBLE_ADDR_TYPE addr_type,tBT_TRANSPORT transport,bthh_status_t,int idle_time)179 static void get_idle_time_callback(RawAddress* bd_addr,
180 tBLE_ADDR_TYPE addr_type,
181 tBT_TRANSPORT transport,
182 bthh_status_t /* hh_status */,
183 int idle_time) {
184 std::shared_lock<std::shared_timed_mutex> lock(mCallbacks_mutex);
185 CallbackEnv sCallbackEnv(__func__);
186 if (!sCallbackEnv.valid()) return;
187
188 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
189 if (!addr.get()) {
190 log::error("Fail to new jbyteArray bd addr");
191 return;
192 }
193 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetIdleTime, addr.get(),
194 (jint)addr_type, (jint)transport,
195 (jint)idle_time);
196 }
197
198 static bthh_callbacks_t sBluetoothHidCallbacks = {
199 sizeof(sBluetoothHidCallbacks),
200 connection_state_callback,
201 NULL,
202 get_protocol_mode_callback,
203 get_idle_time_callback,
204 get_report_callback,
205 virtual_unplug_callback,
206 handshake_callback};
207
208 // Define native functions
initializeNative(JNIEnv * env,jobject object)209 static void initializeNative(JNIEnv* env, jobject object) {
210 std::unique_lock<std::shared_timed_mutex> lock(mCallbacks_mutex);
211 const bt_interface_t* btInf = getBluetoothInterface();
212 if (btInf == NULL) {
213 log::error("Bluetooth module is not loaded");
214 return;
215 }
216
217 if (sBluetoothHidInterface != NULL) {
218 log::warn("Cleaning up Bluetooth HID Interface before initializing...");
219 sBluetoothHidInterface->cleanup();
220 sBluetoothHidInterface = NULL;
221 }
222
223 if (mCallbacksObj != NULL) {
224 log::warn("Cleaning up Bluetooth GID callback object");
225 env->DeleteGlobalRef(mCallbacksObj);
226 mCallbacksObj = NULL;
227 }
228
229 sBluetoothHidInterface =
230 (bthh_interface_t*)btInf->get_profile_interface(BT_PROFILE_HIDHOST_ID);
231 if (sBluetoothHidInterface == NULL) {
232 log::error("Failed to get Bluetooth HID Interface");
233 return;
234 }
235
236 bt_status_t status = sBluetoothHidInterface->init(&sBluetoothHidCallbacks);
237 if (status != BT_STATUS_SUCCESS) {
238 log::error("Failed to initialize Bluetooth HID, status: {}",
239 bt_status_text(status));
240 sBluetoothHidInterface = NULL;
241 return;
242 }
243
244 mCallbacksObj = env->NewGlobalRef(object);
245 }
246
cleanupNative(JNIEnv * env,jobject)247 static void cleanupNative(JNIEnv* env, jobject /* object */) {
248 std::unique_lock<std::shared_timed_mutex> lock(mCallbacks_mutex);
249 const bt_interface_t* btInf = getBluetoothInterface();
250
251 if (btInf == NULL) {
252 log::error("Bluetooth module is not loaded");
253 return;
254 }
255
256 if (sBluetoothHidInterface != NULL) {
257 log::warn("Cleaning up Bluetooth HID Interface...");
258 sBluetoothHidInterface->cleanup();
259 sBluetoothHidInterface = NULL;
260 }
261
262 if (mCallbacksObj != NULL) {
263 log::warn("Cleaning up Bluetooth GID callback object");
264 env->DeleteGlobalRef(mCallbacksObj);
265 mCallbacksObj = NULL;
266 }
267 }
268
connectHidNative(JNIEnv * env,jobject,jbyteArray address,jint address_type,jint transport)269 static jboolean connectHidNative(JNIEnv* env, jobject /* object */,
270 jbyteArray address, jint address_type,
271 jint transport) {
272 if (!sBluetoothHidInterface) return JNI_FALSE;
273
274 jbyte* addr = env->GetByteArrayElements(address, NULL);
275 if (!addr) {
276 log::error("Bluetooth device address null");
277 return JNI_FALSE;
278 }
279
280 jboolean ret = JNI_TRUE;
281 bt_status_t status = sBluetoothHidInterface->connect(
282 (RawAddress*)addr, (tBLE_ADDR_TYPE)address_type,
283 (tBT_TRANSPORT)transport);
284 if (status != BT_STATUS_SUCCESS && status != BT_STATUS_BUSY) {
285 log::error("Failed HID channel connection, status: {}",
286 bt_status_text(status));
287 ret = JNI_FALSE;
288 }
289 env->ReleaseByteArrayElements(address, addr, 0);
290
291 return ret;
292 }
293
disconnectHidNative(JNIEnv * env,jobject,jbyteArray address,jint address_type,jint transport,jboolean reconnect_allowed)294 static jboolean disconnectHidNative(JNIEnv* env, jobject /* object */,
295 jbyteArray address, jint address_type,
296 jint transport,
297 jboolean reconnect_allowed) {
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 log::error("Bluetooth device address null");
305 return JNI_FALSE;
306 }
307
308 bt_status_t status = sBluetoothHidInterface->disconnect(
309 (RawAddress*)addr, (tBLE_ADDR_TYPE)address_type, (tBT_TRANSPORT)transport,
310 reconnect_allowed);
311 if (status != BT_STATUS_SUCCESS) {
312 log::error("Failed disconnect hid channel, status: {}",
313 bt_status_text(status));
314 ret = JNI_FALSE;
315 }
316 env->ReleaseByteArrayElements(address, addr, 0);
317
318 return ret;
319 }
320
getProtocolModeNative(JNIEnv * env,jobject,jbyteArray address,jint address_type,jint transport)321 static jboolean getProtocolModeNative(JNIEnv* env, jobject /* object */,
322 jbyteArray address, jint address_type,
323 jint transport) {
324 if (!sBluetoothHidInterface) return JNI_FALSE;
325
326 jbyte* addr = env->GetByteArrayElements(address, NULL);
327 if (!addr) {
328 log::error("Bluetooth device address null");
329 return JNI_FALSE;
330 }
331
332 jboolean ret = JNI_TRUE;
333 // TODO: protocolMode is unused by the backend: see b/28908173
334 bthh_protocol_mode_t protocolMode = BTHH_UNSUPPORTED_MODE;
335 bt_status_t status = sBluetoothHidInterface->get_protocol(
336 (RawAddress*)addr, (tBLE_ADDR_TYPE)address_type, (tBT_TRANSPORT)transport,
337 (bthh_protocol_mode_t)protocolMode);
338 if (status != BT_STATUS_SUCCESS) {
339 log::error("Failed get protocol mode, status: {}", bt_status_text(status));
340 ret = JNI_FALSE;
341 }
342 env->ReleaseByteArrayElements(address, addr, 0);
343
344 return ret;
345 }
346
virtualUnPlugNative(JNIEnv * env,jobject,jbyteArray address,jint address_type,jint transport)347 static jboolean virtualUnPlugNative(JNIEnv* env, jobject /* object */,
348 jbyteArray address, jint address_type,
349 jint transport) {
350 if (!sBluetoothHidInterface) return JNI_FALSE;
351
352 jbyte* addr = env->GetByteArrayElements(address, NULL);
353 if (!addr) {
354 log::error("Bluetooth device address null");
355 return JNI_FALSE;
356 }
357
358 jboolean ret = JNI_TRUE;
359 bt_status_t status = sBluetoothHidInterface->virtual_unplug(
360 (RawAddress*)addr, (tBLE_ADDR_TYPE)address_type,
361 (tBT_TRANSPORT)transport);
362 if (status != BT_STATUS_SUCCESS) {
363 log::error("Failed virual unplug, status: {}", bt_status_text(status));
364 ret = JNI_FALSE;
365 }
366 env->ReleaseByteArrayElements(address, addr, 0);
367 return ret;
368 }
369
setProtocolModeNative(JNIEnv * env,jobject,jbyteArray address,jint address_type,jint transport,jint protocolMode)370 static jboolean setProtocolModeNative(JNIEnv* env, jobject /* object */,
371 jbyteArray address, jint address_type,
372 jint transport, jint protocolMode) {
373 if (!sBluetoothHidInterface) return JNI_FALSE;
374
375 log::debug("protocolMode = {}", protocolMode);
376
377 jbyte* addr = env->GetByteArrayElements(address, NULL);
378 if (!addr) {
379 log::error("Bluetooth device address null");
380 return JNI_FALSE;
381 }
382
383 bthh_protocol_mode_t mode;
384 switch (protocolMode) {
385 case 0:
386 mode = BTHH_REPORT_MODE;
387 break;
388 case 1:
389 mode = BTHH_BOOT_MODE;
390 break;
391 default:
392 log::error("Unknown HID protocol mode");
393 return JNI_FALSE;
394 }
395
396 jboolean ret = JNI_TRUE;
397 bt_status_t status = sBluetoothHidInterface->set_protocol(
398 (RawAddress*)addr, (tBLE_ADDR_TYPE)address_type, (tBT_TRANSPORT)transport,
399 mode);
400 if (status != BT_STATUS_SUCCESS) {
401 log::error("Failed set protocol mode, status: {}", bt_status_text(status));
402 ret = JNI_FALSE;
403 }
404 env->ReleaseByteArrayElements(address, addr, 0);
405
406 return ret;
407 }
408
getReportNative(JNIEnv * env,jobject,jbyteArray address,jint address_type,jint transport,jbyte reportType,jbyte reportId,jint bufferSize)409 static jboolean getReportNative(JNIEnv* env, jobject /* object */,
410 jbyteArray address, jint address_type,
411 jint transport, jbyte reportType,
412 jbyte reportId, jint bufferSize) {
413 log::verbose("reportType = {}, reportId = {}, bufferSize = {}", reportType,
414 reportId, bufferSize);
415 if (!sBluetoothHidInterface) return JNI_FALSE;
416
417 jbyte* addr = env->GetByteArrayElements(address, NULL);
418 if (!addr) {
419 log::error("Bluetooth device address null");
420 return JNI_FALSE;
421 }
422
423 jint rType = reportType;
424 jint rId = reportId;
425
426 bt_status_t status = sBluetoothHidInterface->get_report(
427 (RawAddress*)addr, (tBLE_ADDR_TYPE)address_type, (tBT_TRANSPORT)transport,
428 (bthh_report_type_t)rType, (uint8_t)rId, bufferSize);
429 jboolean ret = JNI_TRUE;
430 if (status != BT_STATUS_SUCCESS) {
431 log::error("Failed get report, status: {}", bt_status_text(status));
432 ret = JNI_FALSE;
433 }
434 env->ReleaseByteArrayElements(address, addr, 0);
435
436 return ret;
437 }
438
setReportNative(JNIEnv * env,jobject,jbyteArray address,jint address_type,jint transport,jbyte reportType,jstring report)439 static jboolean setReportNative(JNIEnv* env, jobject /* object */,
440 jbyteArray address, jint address_type,
441 jint transport, jbyte reportType,
442 jstring report) {
443 log::verbose("reportType = {}", reportType);
444 if (!sBluetoothHidInterface) return JNI_FALSE;
445
446 jbyte* addr = env->GetByteArrayElements(address, NULL);
447 if (!addr) {
448 log::error("Bluetooth device address null");
449 return JNI_FALSE;
450 }
451 jint rType = reportType;
452 const char* c_report = env->GetStringUTFChars(report, NULL);
453
454 jboolean ret = JNI_TRUE;
455 bt_status_t status = sBluetoothHidInterface->set_report(
456 (RawAddress*)addr, (tBLE_ADDR_TYPE)address_type, (tBT_TRANSPORT)transport,
457 (bthh_report_type_t)rType, (char*)c_report);
458 if (status != BT_STATUS_SUCCESS) {
459 log::error("Failed set report, status: {}", bt_status_text(status));
460 ret = JNI_FALSE;
461 }
462 env->ReleaseStringUTFChars(report, c_report);
463 env->ReleaseByteArrayElements(address, addr, 0);
464
465 return ret;
466 }
467
sendDataNative(JNIEnv * env,jobject,jbyteArray address,jint address_type,jint transport,jstring report)468 static jboolean sendDataNative(JNIEnv* env, jobject /* object */,
469 jbyteArray address, jint address_type,
470 jint transport, jstring report) {
471 log::verbose("");
472 jboolean ret = JNI_TRUE;
473 if (!sBluetoothHidInterface) return JNI_FALSE;
474
475 jbyte* addr = env->GetByteArrayElements(address, NULL);
476 if (!addr) {
477 log::error("Bluetooth device address null");
478 return JNI_FALSE;
479 }
480
481 const char* c_report = env->GetStringUTFChars(report, NULL);
482
483 bt_status_t status = sBluetoothHidInterface->send_data(
484 (RawAddress*)addr, (tBLE_ADDR_TYPE)address_type, (tBT_TRANSPORT)transport,
485 (char*)c_report);
486 if (status != BT_STATUS_SUCCESS) {
487 log::error("Failed set data, status: {}", bt_status_text(status));
488 ret = JNI_FALSE;
489 }
490 env->ReleaseStringUTFChars(report, c_report);
491 env->ReleaseByteArrayElements(address, addr, 0);
492
493 return ret;
494 }
495
getIdleTimeNative(JNIEnv * env,jobject,jbyteArray address,jint address_type,jint transport)496 static jboolean getIdleTimeNative(JNIEnv* env, jobject /* object */,
497 jbyteArray address, jint address_type,
498 jint transport) {
499 if (!sBluetoothHidInterface) return JNI_FALSE;
500
501 jbyte* addr = env->GetByteArrayElements(address, NULL);
502 if (!addr) {
503 log::error("Bluetooth device address null");
504 return JNI_FALSE;
505 }
506
507 bt_status_t status = sBluetoothHidInterface->get_idle_time(
508 (RawAddress*)addr, (tBLE_ADDR_TYPE)address_type,
509 (tBT_TRANSPORT)transport);
510 if (status != BT_STATUS_SUCCESS) {
511 log::error("Failed get idle time, status: {}", bt_status_text(status));
512 }
513 env->ReleaseByteArrayElements(address, addr, 0);
514
515 return status == BT_STATUS_SUCCESS ? JNI_TRUE : JNI_FALSE;
516 }
517
setIdleTimeNative(JNIEnv * env,jobject,jbyteArray address,jint address_type,jint transport,jbyte idle_time)518 static jboolean setIdleTimeNative(JNIEnv* env, jobject /* object */,
519 jbyteArray address, jint address_type,
520 jint transport, jbyte idle_time) {
521 if (!sBluetoothHidInterface) return JNI_FALSE;
522
523 jbyte* addr = env->GetByteArrayElements(address, NULL);
524 if (!addr) {
525 log::error("Bluetooth device address null");
526 return JNI_FALSE;
527 }
528
529 bt_status_t status = sBluetoothHidInterface->set_idle_time(
530 (RawAddress*)addr, (tBLE_ADDR_TYPE)address_type, (tBT_TRANSPORT)transport,
531 idle_time);
532 if (status != BT_STATUS_SUCCESS) {
533 log::error("Failed set idle time, status: {}", bt_status_text(status));
534 }
535 env->ReleaseByteArrayElements(address, addr, 0);
536
537 return status == BT_STATUS_SUCCESS ? JNI_TRUE : JNI_FALSE;
538 }
539
register_com_android_bluetooth_hid_host(JNIEnv * env)540 int register_com_android_bluetooth_hid_host(JNIEnv* env) {
541 const JNINativeMethod methods[] = {
542 {"initializeNative", "()V", (void*)initializeNative},
543 {"cleanupNative", "()V", (void*)cleanupNative},
544 {"connectHidNative", "([BII)Z", (void*)connectHidNative},
545 {"disconnectHidNative", "([BIIZ)Z", (void*)disconnectHidNative},
546 {"getProtocolModeNative", "([BII)Z", (void*)getProtocolModeNative},
547 {"virtualUnPlugNative", "([BII)Z", (void*)virtualUnPlugNative},
548 {"setProtocolModeNative", "([BIIB)Z", (void*)setProtocolModeNative},
549 {"getReportNative", "([BIIBBI)Z", (void*)getReportNative},
550 {"setReportNative", "([BIIBLjava/lang/String;)Z", (void*)setReportNative},
551 {"sendDataNative", "([BIILjava/lang/String;)Z", (void*)sendDataNative},
552 {"getIdleTimeNative", "([BII)Z", (void*)getIdleTimeNative},
553 {"setIdleTimeNative", "([BIIB)Z", (void*)setIdleTimeNative},
554 };
555 const int result = REGISTER_NATIVE_METHODS(
556 env, "com/android/bluetooth/hid/HidHostNativeInterface", methods);
557 if (result != 0) {
558 return result;
559 }
560
561 const JNIJavaMethod javaMethods[] = {
562 {"onConnectStateChanged", "([BIII)V", &method_onConnectStateChanged},
563 {"onGetProtocolMode", "([BIII)V", &method_onGetProtocolMode},
564 {"onGetReport", "([BII[BI)V", &method_onGetReport},
565 {"onHandshake", "([BIII)V", &method_onHandshake},
566 {"onVirtualUnplug", "([BIII)V", &method_onVirtualUnplug},
567 {"onGetIdleTime", "([BIII)V", &method_onGetIdleTime},
568 };
569 GET_JAVA_METHODS(env, "com/android/bluetooth/hid/HidHostNativeInterface",
570 javaMethods);
571
572 return 0;
573 }
574
575 } // namespace android
576