Loading android/app/AndroidManifest.xml +7 −0 Original line number Original line Diff line number Diff line Loading @@ -394,5 +394,12 @@ android:name="android.accounts.AccountAuthenticator" android:name="android.accounts.AccountAuthenticator" android:resource="@xml/authenticator" /> android:resource="@xml/authenticator" /> </service> </service> <service android:name = ".hid.HidDevService" android:enabled="@bool/profile_supported_hidd"> <intent-filter> <action android:name="android.bluetooth.IBluetoothHidDevice" /> </intent-filter> </service> </application> </application> </manifest> </manifest> android/app/jni/Android.mk +1 −0 Original line number Original line Diff line number Diff line Loading @@ -11,6 +11,7 @@ LOCAL_SRC_FILES:= \ com_android_bluetooth_avrcp.cpp \ com_android_bluetooth_avrcp.cpp \ com_android_bluetooth_avrcp_controller.cpp \ com_android_bluetooth_avrcp_controller.cpp \ com_android_bluetooth_hid.cpp \ com_android_bluetooth_hid.cpp \ com_android_bluetooth_hidd.cpp \ com_android_bluetooth_hdp.cpp \ com_android_bluetooth_hdp.cpp \ com_android_bluetooth_pan.cpp \ com_android_bluetooth_pan.cpp \ com_android_bluetooth_gatt.cpp \ com_android_bluetooth_gatt.cpp \ Loading android/app/jni/com_android_bluetooth.h +2 −0 Original line number Original line Diff line number Diff line Loading @@ -84,6 +84,8 @@ int register_com_android_bluetooth_avrcp_controller(JNIEnv* env); int register_com_android_bluetooth_hid(JNIEnv* env); int register_com_android_bluetooth_hid(JNIEnv* env); int register_com_android_bluetooth_hidd(JNIEnv* env); int register_com_android_bluetooth_hdp(JNIEnv* env); int register_com_android_bluetooth_hdp(JNIEnv* env); int register_com_android_bluetooth_pan(JNIEnv* env); int register_com_android_bluetooth_pan(JNIEnv* env); Loading android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp +6 −0 Original line number Original line Diff line number Diff line Loading @@ -1321,6 +1321,12 @@ jint JNI_OnLoad(JavaVM* jvm, void* reserved) { return JNI_ERR; return JNI_ERR; } } status = android::register_com_android_bluetooth_hidd(e); if (status < 0) { ALOGE("jni hidd registration failure: %d", status); return JNI_ERR; } status = android::register_com_android_bluetooth_hdp(e); status = android::register_com_android_bluetooth_hdp(e); if (status < 0) { if (status < 0) { ALOGE("jni hdp registration failure: %d", status); ALOGE("jni hdp registration failure: %d", status); Loading android/app/jni/com_android_bluetooth_hidd.cpp 0 → 100644 +504 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "BluetoothHidDevServiceJni" #define LOG_NDEBUG 0 #define CHECK_CALLBACK_ENV \ if (!checkCallbackThread()) { \ ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \ return; \ } #include "android_runtime/AndroidRuntime.h" #include "com_android_bluetooth.h" #include "hardware/bt_hd.h" #include "utils/Log.h" #include <string.h> namespace android { static jmethodID method_onApplicationStateChanged; static jmethodID method_onConnectStateChanged; static jmethodID method_onGetReport; static jmethodID method_onSetReport; static jmethodID method_onSetProtocol; static jmethodID method_onIntrData; static jmethodID method_onVirtualCableUnplug; static const bthd_interface_t* sHiddIf = NULL; static jobject mCallbacksObj = NULL; static JNIEnv* sCallbackEnv = NULL; static bool checkCallbackThread() { sCallbackEnv = getCallbackEnv(); if (sCallbackEnv != AndroidRuntime::getJNIEnv() || sCallbackEnv == NULL) { return false; } return true; } static void application_state_callback(bt_bdaddr_t* bd_addr, bthd_application_state_t state) { jboolean registered = JNI_FALSE; jbyteArray addr; CHECK_CALLBACK_ENV if (state == BTHD_APP_STATE_REGISTERED) { registered = JNI_TRUE; } if (bd_addr) { addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); if (!addr) { ALOGE("%s: failed to allocate storage for bt_addr", __FUNCTION__); return; } sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*)bd_addr); } else { addr = NULL; } sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onApplicationStateChanged, addr, registered); if (addr) { sCallbackEnv->DeleteLocalRef(addr); } } static void connection_state_callback(bt_bdaddr_t* bd_addr, bthd_connection_state_t state) { jbyteArray addr; CHECK_CALLBACK_ENV addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); if (!addr) { ALOGE("%s: failed to allocate storage for bt_addr", __FUNCTION__); return; } sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*)bd_addr); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectStateChanged, addr, (jint)state); sCallbackEnv->DeleteLocalRef(addr); } static void get_report_callback(uint8_t type, uint8_t id, uint16_t buffer_size) { CHECK_CALLBACK_ENV sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetReport, type, id, buffer_size); } static void set_report_callback(uint8_t type, uint8_t id, uint16_t len, uint8_t* p_data) { jbyteArray data; CHECK_CALLBACK_ENV data = sCallbackEnv->NewByteArray(len); if (!data) { ALOGE("%s: failed to allocate storage for report data", __FUNCTION__); return; } sCallbackEnv->SetByteArrayRegion(data, 0, len, (jbyte*)p_data); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onSetReport, (jbyte)type, (jbyte)id, data); sCallbackEnv->DeleteLocalRef(data); } static void set_protocol_callback(uint8_t protocol) { CHECK_CALLBACK_ENV sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onSetProtocol, protocol); } static void intr_data_callback(uint8_t report_id, uint16_t len, uint8_t* p_data) { jbyteArray data; CHECK_CALLBACK_ENV data = sCallbackEnv->NewByteArray(len); if (!data) { ALOGE("%s: failed to allocate storage for report data", __FUNCTION__); return; } sCallbackEnv->SetByteArrayRegion(data, 0, len, (jbyte*)p_data); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onIntrData, (jbyte)report_id, data); sCallbackEnv->DeleteLocalRef(data); } static void vc_unplug_callback(void) { CHECK_CALLBACK_ENV sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVirtualCableUnplug); } static bthd_callbacks_t sHiddCb = { sizeof(sHiddCb), application_state_callback, connection_state_callback, get_report_callback, set_report_callback, set_protocol_callback, intr_data_callback, vc_unplug_callback, }; static void classInitNative(JNIEnv* env, jclass clazz) { ALOGV("%s: done", __FUNCTION__); method_onApplicationStateChanged = env->GetMethodID(clazz, "onApplicationStateChanged", "([BZ)V"); method_onConnectStateChanged = env->GetMethodID(clazz, "onConnectStateChanged", "([BI)V"); method_onGetReport = env->GetMethodID(clazz, "onGetReport", "(BBS)V"); method_onSetReport = env->GetMethodID(clazz, "onSetReport", "(BB[B)V"); method_onSetProtocol = env->GetMethodID(clazz, "onSetProtocol", "(B)V"); method_onIntrData = env->GetMethodID(clazz, "onIntrData", "(B[B)V"); method_onVirtualCableUnplug = env->GetMethodID(clazz, "onVirtualCableUnplug", "()V"); } static void initNative(JNIEnv* env, jobject object) { const bt_interface_t* btif; bt_status_t status; ALOGV("%s enter", __FUNCTION__); if ((btif = getBluetoothInterface()) == NULL) { ALOGE("Cannot obtain BT interface"); return; } if (sHiddIf != NULL) { ALOGW("Cleaning up interface"); sHiddIf->cleanup(); sHiddIf = NULL; } if (mCallbacksObj != NULL) { ALOGW("Cleaning up callback object"); env->DeleteGlobalRef(mCallbacksObj); mCallbacksObj = NULL; } if ((sHiddIf = (bthd_interface_t*)btif->get_profile_interface( BT_PROFILE_HIDDEV_ID)) == NULL) { ALOGE("Cannot obtain interface"); return; } if ((status = sHiddIf->init(&sHiddCb)) != BT_STATUS_SUCCESS) { ALOGE("Failed to initialize interface (%d)", status); sHiddIf = NULL; return; } mCallbacksObj = env->NewGlobalRef(object); ALOGV("%s done", __FUNCTION__); } static void cleanupNative(JNIEnv* env, jobject object) { ALOGV("%s enter", __FUNCTION__); if (sHiddIf != NULL) { ALOGI("Cleaning up interface"); sHiddIf->cleanup(); sHiddIf = NULL; } if (mCallbacksObj != NULL) { ALOGI("Cleaning up callback object"); env->DeleteGlobalRef(mCallbacksObj); mCallbacksObj = NULL; } ALOGV("%s done", __FUNCTION__); } static void fill_qos(JNIEnv* env, jintArray in, bthd_qos_param_t* out) { // set default values out->service_type = 0x01; // best effort out->token_rate = out->token_bucket_size = out->peak_bandwidth = 0; // don't care out->access_latency = out->delay_variation = 0xffffffff; // don't care if (in == NULL) return; jsize len = env->GetArrayLength(in); if (len != 6) return; uint32_t* buf = (uint32_t*)calloc(len, sizeof(uint32_t)); if (buf == NULL) return; env->GetIntArrayRegion(in, 0, len, (jint*)buf); out->service_type = (uint8_t)buf[0]; out->token_rate = buf[1]; out->token_bucket_size = buf[2]; out->peak_bandwidth = buf[3]; out->access_latency = buf[4]; out->delay_variation = buf[5]; free(buf); } static jboolean registerAppNative(JNIEnv* env, jobject thiz, jstring name, jstring description, jstring provider, jbyte subclass, jbyteArray descriptors, jintArray p_in_qos, jintArray p_out_qos) { ALOGV("%s enter", __FUNCTION__); jboolean result = JNI_FALSE; bthd_app_param_t app_param; bthd_qos_param_t in_qos; bthd_qos_param_t out_qos; jsize size; uint8_t* data; size = env->GetArrayLength(descriptors); data = (uint8_t*)malloc(size); if (data != NULL) { env->GetByteArrayRegion(descriptors, 0, size, (jbyte*)data); app_param.name = env->GetStringUTFChars(name, NULL); app_param.description = env->GetStringUTFChars(description, NULL); app_param.provider = env->GetStringUTFChars(provider, NULL); app_param.subclass = subclass; app_param.desc_list = data; app_param.desc_list_len = size; fill_qos(env, p_in_qos, &in_qos); fill_qos(env, p_out_qos, &out_qos); bt_status_t ret = sHiddIf->register_app(&app_param, &in_qos, &out_qos); ALOGV("%s: register_app() returned %d", __FUNCTION__, ret); if (ret == BT_STATUS_SUCCESS) { result = JNI_TRUE; } env->ReleaseStringUTFChars(name, app_param.name); env->ReleaseStringUTFChars(description, app_param.description); env->ReleaseStringUTFChars(provider, app_param.provider); free(data); } ALOGV("%s done (%d)", __FUNCTION__, result); return result; } static jboolean unregisterAppNative(JNIEnv* env, jobject thiz) { ALOGV("%s enter", __FUNCTION__); jboolean result = JNI_FALSE; bt_status_t ret = sHiddIf->unregister_app(); ALOGV("%s: unregister_app() returned %d", __FUNCTION__, ret); if (ret == BT_STATUS_SUCCESS) { result = JNI_TRUE; } ALOGV("%s done (%d)", __FUNCTION__, result); return result; } static jboolean sendReportNative(JNIEnv* env, jobject thiz, jint id, jbyteArray data) { ALOGV("%s enter", __FUNCTION__); jboolean result = JNI_FALSE; jsize size; uint8_t* buf; size = env->GetArrayLength(data); buf = (uint8_t*)malloc(size); if (buf != NULL) { env->GetByteArrayRegion(data, 0, size, (jbyte*)buf); bt_status_t ret = sHiddIf->send_report(BTHD_REPORT_TYPE_INTRDATA, id, size, buf); ALOGV("%s: send_report() returned %d", __FUNCTION__, ret); if (ret == BT_STATUS_SUCCESS) { result = JNI_TRUE; } free(buf); } ALOGV("%s done (%d)", __FUNCTION__, result); return result; } static jboolean replyReportNative(JNIEnv* env, jobject thiz, jbyte type, jbyte id, jbyteArray data) { ALOGV("%s enter", __FUNCTION__); jboolean result = JNI_FALSE; jsize size; uint8_t* buf; size = env->GetArrayLength(data); buf = (uint8_t*)malloc(size); if (buf != NULL) { int report_type = (type & 0x03); env->GetByteArrayRegion(data, 0, size, (jbyte*)buf); bt_status_t ret = sHiddIf->send_report((bthd_report_type_t)report_type, id, size, buf); ALOGV("%s: send_report() returned %d", __FUNCTION__, ret); if (ret == BT_STATUS_SUCCESS) { result = JNI_TRUE; } free(buf); } ALOGV("%s done (%d)", __FUNCTION__, result); return result; } static jboolean reportErrorNative(JNIEnv* env, jobject thiz, jbyte error) { ALOGV("%s enter", __FUNCTION__); jboolean result = JNI_FALSE; bt_status_t ret = sHiddIf->report_error(error); ALOGV("%s: report_error() returned %d", __FUNCTION__, ret); if (ret == BT_STATUS_SUCCESS) { result = JNI_TRUE; } ALOGV("%s done (%d)", __FUNCTION__, result); return result; } static jboolean unplugNative(JNIEnv* env, jobject thiz) { ALOGV("%s enter", __FUNCTION__); jboolean result = JNI_FALSE; bt_status_t ret = sHiddIf->virtual_cable_unplug(); ALOGV("%s: virtual_cable_unplug() returned %d", __FUNCTION__, ret); if (ret == BT_STATUS_SUCCESS) { result = JNI_TRUE; } ALOGV("%s done (%d)", __FUNCTION__, result); return result; } static jboolean connectNative(JNIEnv* env, jobject thiz) { ALOGV("%s enter", __FUNCTION__); jboolean result = JNI_FALSE; bt_status_t ret = sHiddIf->connect(); ALOGV("%s: connect() returned %d", __FUNCTION__, ret); if (ret == BT_STATUS_SUCCESS) { result = JNI_TRUE; } ALOGV("%s done (%d)", __FUNCTION__, result); return result; } static jboolean disconnectNative(JNIEnv* env, jobject thiz) { ALOGV("%s enter", __FUNCTION__); jboolean result = JNI_FALSE; bt_status_t ret = sHiddIf->disconnect(); ALOGV("%s: disconnect() returned %d", __FUNCTION__, ret); if (ret == BT_STATUS_SUCCESS) { result = JNI_TRUE; } ALOGV("%s done (%d)", __FUNCTION__, result); return result; } static JNINativeMethod sMethods[] = { {"classInitNative", "()V", (void*)classInitNative}, {"initNative", "()V", (void*)initNative}, {"cleanupNative", "()V", (void*)cleanupNative}, {"registerAppNative", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;B[B[I[I)Z", (void*)registerAppNative}, {"unregisterAppNative", "()Z", (void*)unregisterAppNative}, {"sendReportNative", "(I[B)Z", (void*)sendReportNative}, {"replyReportNative", "(BB[B)Z", (void*)replyReportNative}, {"reportErrorNative", "(B)Z", (void*)reportErrorNative}, {"unplugNative", "()Z", (void*)unplugNative}, {"connectNative", "()Z", (void*)connectNative}, {"disconnectNative", "()Z", (void*)disconnectNative}, }; int register_com_android_bluetooth_hidd(JNIEnv* env) { return jniRegisterNativeMethods(env, "com/android/bluetooth/hid/HidDevService", sMethods, NELEM(sMethods)); } } Loading
android/app/AndroidManifest.xml +7 −0 Original line number Original line Diff line number Diff line Loading @@ -394,5 +394,12 @@ android:name="android.accounts.AccountAuthenticator" android:name="android.accounts.AccountAuthenticator" android:resource="@xml/authenticator" /> android:resource="@xml/authenticator" /> </service> </service> <service android:name = ".hid.HidDevService" android:enabled="@bool/profile_supported_hidd"> <intent-filter> <action android:name="android.bluetooth.IBluetoothHidDevice" /> </intent-filter> </service> </application> </application> </manifest> </manifest>
android/app/jni/Android.mk +1 −0 Original line number Original line Diff line number Diff line Loading @@ -11,6 +11,7 @@ LOCAL_SRC_FILES:= \ com_android_bluetooth_avrcp.cpp \ com_android_bluetooth_avrcp.cpp \ com_android_bluetooth_avrcp_controller.cpp \ com_android_bluetooth_avrcp_controller.cpp \ com_android_bluetooth_hid.cpp \ com_android_bluetooth_hid.cpp \ com_android_bluetooth_hidd.cpp \ com_android_bluetooth_hdp.cpp \ com_android_bluetooth_hdp.cpp \ com_android_bluetooth_pan.cpp \ com_android_bluetooth_pan.cpp \ com_android_bluetooth_gatt.cpp \ com_android_bluetooth_gatt.cpp \ Loading
android/app/jni/com_android_bluetooth.h +2 −0 Original line number Original line Diff line number Diff line Loading @@ -84,6 +84,8 @@ int register_com_android_bluetooth_avrcp_controller(JNIEnv* env); int register_com_android_bluetooth_hid(JNIEnv* env); int register_com_android_bluetooth_hid(JNIEnv* env); int register_com_android_bluetooth_hidd(JNIEnv* env); int register_com_android_bluetooth_hdp(JNIEnv* env); int register_com_android_bluetooth_hdp(JNIEnv* env); int register_com_android_bluetooth_pan(JNIEnv* env); int register_com_android_bluetooth_pan(JNIEnv* env); Loading
android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp +6 −0 Original line number Original line Diff line number Diff line Loading @@ -1321,6 +1321,12 @@ jint JNI_OnLoad(JavaVM* jvm, void* reserved) { return JNI_ERR; return JNI_ERR; } } status = android::register_com_android_bluetooth_hidd(e); if (status < 0) { ALOGE("jni hidd registration failure: %d", status); return JNI_ERR; } status = android::register_com_android_bluetooth_hdp(e); status = android::register_com_android_bluetooth_hdp(e); if (status < 0) { if (status < 0) { ALOGE("jni hdp registration failure: %d", status); ALOGE("jni hdp registration failure: %d", status); Loading
android/app/jni/com_android_bluetooth_hidd.cpp 0 → 100644 +504 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "BluetoothHidDevServiceJni" #define LOG_NDEBUG 0 #define CHECK_CALLBACK_ENV \ if (!checkCallbackThread()) { \ ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \ return; \ } #include "android_runtime/AndroidRuntime.h" #include "com_android_bluetooth.h" #include "hardware/bt_hd.h" #include "utils/Log.h" #include <string.h> namespace android { static jmethodID method_onApplicationStateChanged; static jmethodID method_onConnectStateChanged; static jmethodID method_onGetReport; static jmethodID method_onSetReport; static jmethodID method_onSetProtocol; static jmethodID method_onIntrData; static jmethodID method_onVirtualCableUnplug; static const bthd_interface_t* sHiddIf = NULL; static jobject mCallbacksObj = NULL; static JNIEnv* sCallbackEnv = NULL; static bool checkCallbackThread() { sCallbackEnv = getCallbackEnv(); if (sCallbackEnv != AndroidRuntime::getJNIEnv() || sCallbackEnv == NULL) { return false; } return true; } static void application_state_callback(bt_bdaddr_t* bd_addr, bthd_application_state_t state) { jboolean registered = JNI_FALSE; jbyteArray addr; CHECK_CALLBACK_ENV if (state == BTHD_APP_STATE_REGISTERED) { registered = JNI_TRUE; } if (bd_addr) { addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); if (!addr) { ALOGE("%s: failed to allocate storage for bt_addr", __FUNCTION__); return; } sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*)bd_addr); } else { addr = NULL; } sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onApplicationStateChanged, addr, registered); if (addr) { sCallbackEnv->DeleteLocalRef(addr); } } static void connection_state_callback(bt_bdaddr_t* bd_addr, bthd_connection_state_t state) { jbyteArray addr; CHECK_CALLBACK_ENV addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); if (!addr) { ALOGE("%s: failed to allocate storage for bt_addr", __FUNCTION__); return; } sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*)bd_addr); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectStateChanged, addr, (jint)state); sCallbackEnv->DeleteLocalRef(addr); } static void get_report_callback(uint8_t type, uint8_t id, uint16_t buffer_size) { CHECK_CALLBACK_ENV sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetReport, type, id, buffer_size); } static void set_report_callback(uint8_t type, uint8_t id, uint16_t len, uint8_t* p_data) { jbyteArray data; CHECK_CALLBACK_ENV data = sCallbackEnv->NewByteArray(len); if (!data) { ALOGE("%s: failed to allocate storage for report data", __FUNCTION__); return; } sCallbackEnv->SetByteArrayRegion(data, 0, len, (jbyte*)p_data); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onSetReport, (jbyte)type, (jbyte)id, data); sCallbackEnv->DeleteLocalRef(data); } static void set_protocol_callback(uint8_t protocol) { CHECK_CALLBACK_ENV sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onSetProtocol, protocol); } static void intr_data_callback(uint8_t report_id, uint16_t len, uint8_t* p_data) { jbyteArray data; CHECK_CALLBACK_ENV data = sCallbackEnv->NewByteArray(len); if (!data) { ALOGE("%s: failed to allocate storage for report data", __FUNCTION__); return; } sCallbackEnv->SetByteArrayRegion(data, 0, len, (jbyte*)p_data); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onIntrData, (jbyte)report_id, data); sCallbackEnv->DeleteLocalRef(data); } static void vc_unplug_callback(void) { CHECK_CALLBACK_ENV sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVirtualCableUnplug); } static bthd_callbacks_t sHiddCb = { sizeof(sHiddCb), application_state_callback, connection_state_callback, get_report_callback, set_report_callback, set_protocol_callback, intr_data_callback, vc_unplug_callback, }; static void classInitNative(JNIEnv* env, jclass clazz) { ALOGV("%s: done", __FUNCTION__); method_onApplicationStateChanged = env->GetMethodID(clazz, "onApplicationStateChanged", "([BZ)V"); method_onConnectStateChanged = env->GetMethodID(clazz, "onConnectStateChanged", "([BI)V"); method_onGetReport = env->GetMethodID(clazz, "onGetReport", "(BBS)V"); method_onSetReport = env->GetMethodID(clazz, "onSetReport", "(BB[B)V"); method_onSetProtocol = env->GetMethodID(clazz, "onSetProtocol", "(B)V"); method_onIntrData = env->GetMethodID(clazz, "onIntrData", "(B[B)V"); method_onVirtualCableUnplug = env->GetMethodID(clazz, "onVirtualCableUnplug", "()V"); } static void initNative(JNIEnv* env, jobject object) { const bt_interface_t* btif; bt_status_t status; ALOGV("%s enter", __FUNCTION__); if ((btif = getBluetoothInterface()) == NULL) { ALOGE("Cannot obtain BT interface"); return; } if (sHiddIf != NULL) { ALOGW("Cleaning up interface"); sHiddIf->cleanup(); sHiddIf = NULL; } if (mCallbacksObj != NULL) { ALOGW("Cleaning up callback object"); env->DeleteGlobalRef(mCallbacksObj); mCallbacksObj = NULL; } if ((sHiddIf = (bthd_interface_t*)btif->get_profile_interface( BT_PROFILE_HIDDEV_ID)) == NULL) { ALOGE("Cannot obtain interface"); return; } if ((status = sHiddIf->init(&sHiddCb)) != BT_STATUS_SUCCESS) { ALOGE("Failed to initialize interface (%d)", status); sHiddIf = NULL; return; } mCallbacksObj = env->NewGlobalRef(object); ALOGV("%s done", __FUNCTION__); } static void cleanupNative(JNIEnv* env, jobject object) { ALOGV("%s enter", __FUNCTION__); if (sHiddIf != NULL) { ALOGI("Cleaning up interface"); sHiddIf->cleanup(); sHiddIf = NULL; } if (mCallbacksObj != NULL) { ALOGI("Cleaning up callback object"); env->DeleteGlobalRef(mCallbacksObj); mCallbacksObj = NULL; } ALOGV("%s done", __FUNCTION__); } static void fill_qos(JNIEnv* env, jintArray in, bthd_qos_param_t* out) { // set default values out->service_type = 0x01; // best effort out->token_rate = out->token_bucket_size = out->peak_bandwidth = 0; // don't care out->access_latency = out->delay_variation = 0xffffffff; // don't care if (in == NULL) return; jsize len = env->GetArrayLength(in); if (len != 6) return; uint32_t* buf = (uint32_t*)calloc(len, sizeof(uint32_t)); if (buf == NULL) return; env->GetIntArrayRegion(in, 0, len, (jint*)buf); out->service_type = (uint8_t)buf[0]; out->token_rate = buf[1]; out->token_bucket_size = buf[2]; out->peak_bandwidth = buf[3]; out->access_latency = buf[4]; out->delay_variation = buf[5]; free(buf); } static jboolean registerAppNative(JNIEnv* env, jobject thiz, jstring name, jstring description, jstring provider, jbyte subclass, jbyteArray descriptors, jintArray p_in_qos, jintArray p_out_qos) { ALOGV("%s enter", __FUNCTION__); jboolean result = JNI_FALSE; bthd_app_param_t app_param; bthd_qos_param_t in_qos; bthd_qos_param_t out_qos; jsize size; uint8_t* data; size = env->GetArrayLength(descriptors); data = (uint8_t*)malloc(size); if (data != NULL) { env->GetByteArrayRegion(descriptors, 0, size, (jbyte*)data); app_param.name = env->GetStringUTFChars(name, NULL); app_param.description = env->GetStringUTFChars(description, NULL); app_param.provider = env->GetStringUTFChars(provider, NULL); app_param.subclass = subclass; app_param.desc_list = data; app_param.desc_list_len = size; fill_qos(env, p_in_qos, &in_qos); fill_qos(env, p_out_qos, &out_qos); bt_status_t ret = sHiddIf->register_app(&app_param, &in_qos, &out_qos); ALOGV("%s: register_app() returned %d", __FUNCTION__, ret); if (ret == BT_STATUS_SUCCESS) { result = JNI_TRUE; } env->ReleaseStringUTFChars(name, app_param.name); env->ReleaseStringUTFChars(description, app_param.description); env->ReleaseStringUTFChars(provider, app_param.provider); free(data); } ALOGV("%s done (%d)", __FUNCTION__, result); return result; } static jboolean unregisterAppNative(JNIEnv* env, jobject thiz) { ALOGV("%s enter", __FUNCTION__); jboolean result = JNI_FALSE; bt_status_t ret = sHiddIf->unregister_app(); ALOGV("%s: unregister_app() returned %d", __FUNCTION__, ret); if (ret == BT_STATUS_SUCCESS) { result = JNI_TRUE; } ALOGV("%s done (%d)", __FUNCTION__, result); return result; } static jboolean sendReportNative(JNIEnv* env, jobject thiz, jint id, jbyteArray data) { ALOGV("%s enter", __FUNCTION__); jboolean result = JNI_FALSE; jsize size; uint8_t* buf; size = env->GetArrayLength(data); buf = (uint8_t*)malloc(size); if (buf != NULL) { env->GetByteArrayRegion(data, 0, size, (jbyte*)buf); bt_status_t ret = sHiddIf->send_report(BTHD_REPORT_TYPE_INTRDATA, id, size, buf); ALOGV("%s: send_report() returned %d", __FUNCTION__, ret); if (ret == BT_STATUS_SUCCESS) { result = JNI_TRUE; } free(buf); } ALOGV("%s done (%d)", __FUNCTION__, result); return result; } static jboolean replyReportNative(JNIEnv* env, jobject thiz, jbyte type, jbyte id, jbyteArray data) { ALOGV("%s enter", __FUNCTION__); jboolean result = JNI_FALSE; jsize size; uint8_t* buf; size = env->GetArrayLength(data); buf = (uint8_t*)malloc(size); if (buf != NULL) { int report_type = (type & 0x03); env->GetByteArrayRegion(data, 0, size, (jbyte*)buf); bt_status_t ret = sHiddIf->send_report((bthd_report_type_t)report_type, id, size, buf); ALOGV("%s: send_report() returned %d", __FUNCTION__, ret); if (ret == BT_STATUS_SUCCESS) { result = JNI_TRUE; } free(buf); } ALOGV("%s done (%d)", __FUNCTION__, result); return result; } static jboolean reportErrorNative(JNIEnv* env, jobject thiz, jbyte error) { ALOGV("%s enter", __FUNCTION__); jboolean result = JNI_FALSE; bt_status_t ret = sHiddIf->report_error(error); ALOGV("%s: report_error() returned %d", __FUNCTION__, ret); if (ret == BT_STATUS_SUCCESS) { result = JNI_TRUE; } ALOGV("%s done (%d)", __FUNCTION__, result); return result; } static jboolean unplugNative(JNIEnv* env, jobject thiz) { ALOGV("%s enter", __FUNCTION__); jboolean result = JNI_FALSE; bt_status_t ret = sHiddIf->virtual_cable_unplug(); ALOGV("%s: virtual_cable_unplug() returned %d", __FUNCTION__, ret); if (ret == BT_STATUS_SUCCESS) { result = JNI_TRUE; } ALOGV("%s done (%d)", __FUNCTION__, result); return result; } static jboolean connectNative(JNIEnv* env, jobject thiz) { ALOGV("%s enter", __FUNCTION__); jboolean result = JNI_FALSE; bt_status_t ret = sHiddIf->connect(); ALOGV("%s: connect() returned %d", __FUNCTION__, ret); if (ret == BT_STATUS_SUCCESS) { result = JNI_TRUE; } ALOGV("%s done (%d)", __FUNCTION__, result); return result; } static jboolean disconnectNative(JNIEnv* env, jobject thiz) { ALOGV("%s enter", __FUNCTION__); jboolean result = JNI_FALSE; bt_status_t ret = sHiddIf->disconnect(); ALOGV("%s: disconnect() returned %d", __FUNCTION__, ret); if (ret == BT_STATUS_SUCCESS) { result = JNI_TRUE; } ALOGV("%s done (%d)", __FUNCTION__, result); return result; } static JNINativeMethod sMethods[] = { {"classInitNative", "()V", (void*)classInitNative}, {"initNative", "()V", (void*)initNative}, {"cleanupNative", "()V", (void*)cleanupNative}, {"registerAppNative", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;B[B[I[I)Z", (void*)registerAppNative}, {"unregisterAppNative", "()Z", (void*)unregisterAppNative}, {"sendReportNative", "(I[B)Z", (void*)sendReportNative}, {"replyReportNative", "(BB[B)Z", (void*)replyReportNative}, {"reportErrorNative", "(B)Z", (void*)reportErrorNative}, {"unplugNative", "()Z", (void*)unplugNative}, {"connectNative", "()Z", (void*)connectNative}, {"disconnectNative", "()Z", (void*)disconnectNative}, }; int register_com_android_bluetooth_hidd(JNIEnv* env) { return jniRegisterNativeMethods(env, "com/android/bluetooth/hid/HidDevService", sMethods, NELEM(sMethods)); } }