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