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