Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "BluetoothHidServiceJni"
     18 
     19 #define LOG_NDEBUG 1
     20 
     21 #define CHECK_CALLBACK_ENV                                                      \
     22    if (!checkCallbackThread()) {                                                \
     23        ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);\
     24        return;                                                                  \
     25    }
     26 
     27 #include "com_android_bluetooth.h"
     28 #include "hardware/bt_hh.h"
     29 #include "utils/Log.h"
     30 #include "android_runtime/AndroidRuntime.h"
     31 
     32 #include <string.h>
     33 
     34 namespace android {
     35 
     36 static jmethodID method_onConnectStateChanged;
     37 static jmethodID method_onGetProtocolMode;
     38 static jmethodID method_onGetReport;
     39 static jmethodID method_onHandshake;
     40 static jmethodID method_onVirtualUnplug;
     41 
     42 static const bthh_interface_t *sBluetoothHidInterface = NULL;
     43 static jobject mCallbacksObj = NULL;
     44 static JNIEnv *sCallbackEnv = NULL;
     45 
     46 static bool checkCallbackThread() {
     47 
     48     // Always fetch the latest callbackEnv from AdapterService.
     49     // Caching this could cause this sCallbackEnv to go out-of-sync
     50     // with the AdapterService's ENV if an ASSOCIATE/DISASSOCIATE event
     51     // is received
     52 
     53     sCallbackEnv = getCallbackEnv();
     54 
     55     JNIEnv* env = AndroidRuntime::getJNIEnv();
     56     if (sCallbackEnv != env || sCallbackEnv == NULL) return false;
     57     return true;
     58 }
     59 
     60 static void connection_state_callback(bt_bdaddr_t *bd_addr, bthh_connection_state_t state) {
     61     jbyteArray addr;
     62 
     63     CHECK_CALLBACK_ENV
     64     addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
     65     if (!addr) {
     66         ALOGE("Fail to new jbyteArray bd addr for HID channel state");
     67         checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
     68         return;
     69     }
     70     sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
     71 
     72     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectStateChanged, addr, (jint) state);
     73     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
     74     sCallbackEnv->DeleteLocalRef(addr);
     75 }
     76 
     77 static void get_protocol_mode_callback(bt_bdaddr_t *bd_addr, bthh_status_t hh_status,bthh_protocol_mode_t mode) {
     78     jbyteArray addr;
     79 
     80     CHECK_CALLBACK_ENV
     81     if (hh_status != BTHH_OK) {
     82         ALOGE("BTHH Status is not OK!");
     83         checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
     84         return;
     85     }
     86 
     87     addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
     88     if (!addr) {
     89         ALOGE("Fail to new jbyteArray bd addr for get protocal mode callback");
     90         checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
     91         return;
     92     }
     93     sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
     94 
     95     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetProtocolMode, addr, (jint) mode);
     96     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
     97     sCallbackEnv->DeleteLocalRef(addr);
     98 }
     99 
    100 static void get_report_callback(bt_bdaddr_t *bd_addr, bthh_status_t hh_status, uint8_t *rpt_data, int rpt_size) {
    101     jbyteArray addr;
    102     jbyteArray data;
    103 
    104     CHECK_CALLBACK_ENV
    105     if (hh_status != BTHH_OK) {
    106         ALOGE("BTHH Status is not OK!");
    107         checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    108         return;
    109     }
    110 
    111     addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
    112     if (!addr) {
    113         ALOGE("Fail to new jbyteArray bd addr for get report callback");
    114         checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    115         return;
    116     }
    117     data = sCallbackEnv->NewByteArray(rpt_size);
    118     if (!data) {
    119         ALOGE("Fail to new jbyteArray data for get report callback");
    120         checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    121         sCallbackEnv->DeleteLocalRef(addr);
    122         return;
    123     }
    124 
    125     sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
    126     sCallbackEnv->SetByteArrayRegion(data, 0, rpt_size, (jbyte *) rpt_data);
    127 
    128     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetReport, addr, data, (jint) rpt_size);
    129     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    130     sCallbackEnv->DeleteLocalRef(addr);
    131     sCallbackEnv->DeleteLocalRef(data);
    132 }
    133 
    134 static void virtual_unplug_callback(bt_bdaddr_t *bd_addr, bthh_status_t hh_status) {
    135     ALOGV("call to virtual_unplug_callback");
    136     jbyteArray addr;
    137 
    138     CHECK_CALLBACK_ENV
    139     addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
    140     if (!addr) {
    141         ALOGE("Fail to new jbyteArray bd addr for HID channel state");
    142         checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    143         return;
    144     }
    145     sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
    146 
    147     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVirtualUnplug, addr, (jint) hh_status);
    148     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    149     sCallbackEnv->DeleteLocalRef(addr);
    150 
    151     /*jbyteArray addr;
    152     jint status = hh_status;
    153     CHECK_CALLBACK_ENV
    154     addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
    155     if (!addr) {
    156         ALOGE("Fail to new jbyteArray bd addr for HID report");
    157         checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    158         return;
    159     }
    160     sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
    161 
    162     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVirtualUnplug, addr, status);
    163     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    164     sCallbackEnv->DeleteLocalRef(addr);*/
    165 }
    166 
    167 static void handshake_callback(bt_bdaddr_t *bd_addr, bthh_status_t hh_status)
    168 {
    169     jbyteArray addr;
    170 
    171     CHECK_CALLBACK_ENV
    172 
    173     addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
    174     if (!addr) {
    175         ALOGE("Fail to new jbyteArray bd addr for handshake callback");
    176         checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    177         return;
    178     }
    179     sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
    180     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onHandshake, addr, (jint) hh_status);
    181     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    182     sCallbackEnv->DeleteLocalRef(addr);
    183 }
    184 
    185 static bthh_callbacks_t sBluetoothHidCallbacks = {
    186     sizeof(sBluetoothHidCallbacks),
    187     connection_state_callback,
    188     NULL,
    189     get_protocol_mode_callback,
    190     NULL,
    191     get_report_callback,
    192     virtual_unplug_callback,
    193     handshake_callback
    194 };
    195 
    196 // Define native functions
    197 
    198 static void classInitNative(JNIEnv* env, jclass clazz) {
    199     int err;
    200 //    const bt_interface_t* btInf;
    201 //    bt_status_t status;
    202 
    203     method_onConnectStateChanged = env->GetMethodID(clazz, "onConnectStateChanged", "([BI)V");
    204     method_onGetProtocolMode = env->GetMethodID(clazz, "onGetProtocolMode", "([BI)V");
    205     method_onGetReport = env->GetMethodID(clazz, "onGetReport", "([B[BI)V");
    206     method_onHandshake = env->GetMethodID(clazz, "onHandshake", "([BI)V");
    207     method_onVirtualUnplug = env->GetMethodID(clazz, "onVirtualUnplug", "([BI)V");
    208 
    209 /*
    210     if ( (btInf = getBluetoothInterface()) == NULL) {
    211         ALOGE("Bluetooth module is not loaded");
    212         return;
    213     }
    214 
    215     if ( (sBluetoothHidInterface = (bthh_interface_t *)
    216           btInf->get_profile_interface(BT_PROFILE_HIDHOST_ID)) == NULL) {
    217         ALOGE("Failed to get Bluetooth Handsfree Interface");
    218         return;
    219     }
    220 
    221     // TODO(BT) do this only once or
    222     //          Do we need to do this every time the BT reenables?
    223     if ( (status = sBluetoothHidInterface->init(&sBluetoothHidCallbacks)) != BT_STATUS_SUCCESS) {
    224         ALOGE("Failed to initialize Bluetooth HID, status: %d", status);
    225         sBluetoothHidInterface = NULL;
    226         return;
    227     }
    228 
    229 */
    230     ALOGI("%s: succeeds", __FUNCTION__);
    231 }
    232 
    233 static void initializeNative(JNIEnv *env, jobject object) {
    234     const bt_interface_t* btInf;
    235     bt_status_t status;
    236 
    237     if ( (btInf = getBluetoothInterface()) == NULL) {
    238         ALOGE("Bluetooth module is not loaded");
    239         return;
    240     }
    241 
    242     if (sBluetoothHidInterface !=NULL) {
    243         ALOGW("Cleaning up Bluetooth HID Interface before initializing...");
    244         sBluetoothHidInterface->cleanup();
    245         sBluetoothHidInterface = NULL;
    246     }
    247 
    248     if (mCallbacksObj != NULL) {
    249         ALOGW("Cleaning up Bluetooth GID callback object");
    250         env->DeleteGlobalRef(mCallbacksObj);
    251         mCallbacksObj = NULL;
    252     }
    253 
    254 
    255     if ( (sBluetoothHidInterface = (bthh_interface_t *)
    256           btInf->get_profile_interface(BT_PROFILE_HIDHOST_ID)) == NULL) {
    257         ALOGE("Failed to get Bluetooth HID Interface");
    258         return;
    259     }
    260 
    261     if ( (status = sBluetoothHidInterface->init(&sBluetoothHidCallbacks)) != BT_STATUS_SUCCESS) {
    262         ALOGE("Failed to initialize Bluetooth HID, status: %d", status);
    263         sBluetoothHidInterface = NULL;
    264         return;
    265     }
    266 
    267 
    268 
    269     mCallbacksObj = env->NewGlobalRef(object);
    270 }
    271 
    272 static void cleanupNative(JNIEnv *env, jobject object) {
    273     const bt_interface_t* btInf;
    274     bt_status_t status;
    275 
    276     if ( (btInf = getBluetoothInterface()) == NULL) {
    277         ALOGE("Bluetooth module is not loaded");
    278         return;
    279     }
    280 
    281     if (sBluetoothHidInterface !=NULL) {
    282         ALOGW("Cleaning up Bluetooth HID Interface...");
    283         sBluetoothHidInterface->cleanup();
    284         sBluetoothHidInterface = NULL;
    285     }
    286 
    287     if (mCallbacksObj != NULL) {
    288         ALOGW("Cleaning up Bluetooth GID callback object");
    289         env->DeleteGlobalRef(mCallbacksObj);
    290         mCallbacksObj = NULL;
    291     }
    292 
    293     env->DeleteGlobalRef(mCallbacksObj);
    294 }
    295 
    296 static jboolean connectHidNative(JNIEnv *env, jobject object, jbyteArray address) {
    297     bt_status_t status;
    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         ALOGE("Bluetooth device address null");
    305         return JNI_FALSE;
    306     }
    307 
    308     if ((status = sBluetoothHidInterface->connect((bt_bdaddr_t *) addr)) !=
    309          BT_STATUS_SUCCESS) {
    310         ALOGE("Failed HID channel connection, status: %d", status);
    311         ret = JNI_FALSE;
    312     }
    313     env->ReleaseByteArrayElements(address, addr, 0);
    314 
    315     return ret;
    316 }
    317 
    318 static jboolean disconnectHidNative(JNIEnv *env, jobject object, jbyteArray address) {
    319     bt_status_t status;
    320     jbyte *addr;
    321     jboolean ret = JNI_TRUE;
    322     if (!sBluetoothHidInterface) return JNI_FALSE;
    323 
    324     addr = env->GetByteArrayElements(address, NULL);
    325     if (!addr) {
    326         ALOGE("Bluetooth device address null");
    327         return JNI_FALSE;
    328     }
    329 
    330     if ( (status = sBluetoothHidInterface->disconnect((bt_bdaddr_t *) addr)) !=
    331          BT_STATUS_SUCCESS) {
    332         ALOGE("Failed disconnect hid channel, status: %d", status);
    333         ret = JNI_FALSE;
    334     }
    335     env->ReleaseByteArrayElements(address, addr, 0);
    336 
    337     return ret;
    338 }
    339 
    340 static jboolean getProtocolModeNative(JNIEnv *env, jobject object, jbyteArray address) {
    341     bt_status_t status;
    342     jbyte *addr;
    343     jboolean ret = JNI_TRUE;
    344     bthh_protocol_mode_t protocolMode;
    345     if (!sBluetoothHidInterface) return JNI_FALSE;
    346 
    347     addr = env->GetByteArrayElements(address, NULL);
    348     if (!addr) {
    349         ALOGE("Bluetooth device address null");
    350         return JNI_FALSE;
    351     }
    352 
    353     if ( (status = sBluetoothHidInterface->get_protocol((bt_bdaddr_t *) addr, (bthh_protocol_mode_t) protocolMode)) !=
    354          BT_STATUS_SUCCESS) {
    355         ALOGE("Failed get protocol mode, status: %d", status);
    356         ret = JNI_FALSE;
    357     }
    358     env->ReleaseByteArrayElements(address, addr, 0);
    359 
    360     return ret;
    361 }
    362 
    363 static jboolean virtualUnPlugNative(JNIEnv *env, jobject object, jbyteArray address) {
    364     bt_status_t status;
    365     jbyte *addr;
    366     jboolean ret = JNI_TRUE;
    367     if (!sBluetoothHidInterface) return JNI_FALSE;
    368 
    369     addr = env->GetByteArrayElements(address, NULL);
    370         if (!addr) {
    371             ALOGE("Bluetooth device address null");
    372             return JNI_FALSE;
    373         }
    374     if ( (status = sBluetoothHidInterface->virtual_unplug((bt_bdaddr_t *) addr)) !=
    375              BT_STATUS_SUCCESS) {
    376         ALOGE("Failed virual unplug, status: %d", status);
    377         ret = JNI_FALSE;
    378     }
    379     env->ReleaseByteArrayElements(address, addr, 0);
    380     return ret;
    381 
    382 }
    383 
    384 
    385 static jboolean setProtocolModeNative(JNIEnv *env, jobject object, jbyteArray address, jint protocolMode) {
    386     bt_status_t status;
    387     jbyte *addr;
    388     jboolean ret = JNI_TRUE;
    389     if (!sBluetoothHidInterface) return JNI_FALSE;
    390 
    391     ALOGD("%s: protocolMode = %d", __FUNCTION__, protocolMode);
    392 
    393     addr = env->GetByteArrayElements(address, NULL);
    394     if (!addr) {
    395         ALOGE("Bluetooth device address null");
    396         return JNI_FALSE;
    397     }
    398 
    399     bthh_protocol_mode_t mode;
    400     switch(protocolMode){
    401         case 0:
    402             mode = BTHH_REPORT_MODE;
    403             break;
    404         case 1:
    405             mode = BTHH_BOOT_MODE;
    406             break;
    407         default:
    408             ALOGE("Unknown HID protocol mode");
    409             return JNI_FALSE;
    410     }
    411     if ( (status = sBluetoothHidInterface->set_protocol((bt_bdaddr_t *) addr, mode)) !=
    412              BT_STATUS_SUCCESS) {
    413         ALOGE("Failed set protocol mode, status: %d", status);
    414         ret = JNI_FALSE;
    415     }
    416     env->ReleaseByteArrayElements(address, addr, 0);
    417 
    418     return JNI_TRUE;
    419 }
    420 
    421 static jboolean getReportNative(JNIEnv *env, jobject object, jbyteArray address, jbyte reportType, jbyte reportId, jint bufferSize) {
    422     ALOGV("%s: reportType = %d, reportId = %d, bufferSize = %d", __FUNCTION__, reportType, reportId, bufferSize);
    423 
    424     bt_status_t status;
    425     jbyte *addr;
    426     jboolean ret = JNI_TRUE;
    427     if (!sBluetoothHidInterface) return JNI_FALSE;
    428 
    429     addr = env->GetByteArrayElements(address, NULL);
    430     if (!addr) {
    431         ALOGE("Bluetooth device address null");
    432         return JNI_FALSE;
    433     }
    434 
    435     jint rType = reportType;
    436     jint rId = reportId;
    437 
    438     if ( (status = sBluetoothHidInterface->get_report((bt_bdaddr_t *) addr, (bthh_report_type_t) rType, (uint8_t) rId, bufferSize)) !=
    439              BT_STATUS_SUCCESS) {
    440         ALOGE("Failed get report, status: %d", status);
    441         ret = JNI_FALSE;
    442     }
    443     env->ReleaseByteArrayElements(address, addr, 0);
    444 
    445     return ret;
    446 }
    447 
    448 
    449 static jboolean setReportNative(JNIEnv *env, jobject object, jbyteArray address, jbyte reportType, jstring report) {
    450     ALOGV("%s: reportType = %d", __FUNCTION__, reportType);
    451     bt_status_t status;
    452     jbyte *addr;
    453     jboolean ret = JNI_TRUE;
    454     if (!sBluetoothHidInterface) return JNI_FALSE;
    455 
    456     addr = env->GetByteArrayElements(address, NULL);
    457     if (!addr) {
    458         ALOGE("Bluetooth device address null");
    459         return JNI_FALSE;
    460     }
    461     jint rType = reportType;
    462     const char *c_report = env->GetStringUTFChars(report, NULL);
    463 
    464     if ( (status = sBluetoothHidInterface->set_report((bt_bdaddr_t *) addr, (bthh_report_type_t)rType, (char*) c_report)) !=
    465              BT_STATUS_SUCCESS) {
    466         ALOGE("Failed set report, status: %d", status);
    467         ret = JNI_FALSE;
    468     }
    469     env->ReleaseStringUTFChars(report, c_report);
    470     env->ReleaseByteArrayElements(address, addr, 0);
    471 
    472     return ret;
    473 }
    474 
    475 static jboolean sendDataNative(JNIEnv *env, jobject object, jbyteArray address, jstring report) {
    476     ALOGV("%s", __FUNCTION__);
    477     bt_status_t status;
    478     jbyte *addr;
    479     jboolean ret = JNI_TRUE;
    480     if (!sBluetoothHidInterface) return JNI_FALSE;
    481 
    482     addr = env->GetByteArrayElements(address, NULL);
    483     if (!addr) {
    484         ALOGE("Bluetooth device address null");
    485         return JNI_FALSE;
    486     }
    487     const char *c_report = env->GetStringUTFChars(report, NULL);
    488     if ( (status = sBluetoothHidInterface->send_data((bt_bdaddr_t *) addr, (char*) c_report)) !=
    489              BT_STATUS_SUCCESS) {
    490         ALOGE("Failed set report, status: %d", status);
    491         ret = JNI_FALSE;
    492     }
    493     env->ReleaseStringUTFChars(report, c_report);
    494     env->ReleaseByteArrayElements(address, addr, 0);
    495 
    496     return ret;
    497 
    498 }
    499 
    500 static JNINativeMethod sMethods[] = {
    501     {"classInitNative", "()V", (void *) classInitNative},
    502     {"initializeNative", "()V", (void *) initializeNative},
    503     {"cleanupNative", "()V", (void *) cleanupNative},
    504     {"connectHidNative", "([B)Z", (void *) connectHidNative},
    505     {"disconnectHidNative", "([B)Z", (void *) disconnectHidNative},
    506     {"getProtocolModeNative", "([B)Z", (void *) getProtocolModeNative},
    507     {"virtualUnPlugNative", "([B)Z", (void *) virtualUnPlugNative},
    508     {"setProtocolModeNative", "([BB)Z", (void *) setProtocolModeNative},
    509     {"getReportNative", "([BBBI)Z", (void *) getReportNative},
    510     {"setReportNative", "([BBLjava/lang/String;)Z", (void *) setReportNative},
    511     {"sendDataNative", "([BLjava/lang/String;)Z", (void *) sendDataNative},
    512 };
    513 
    514 int register_com_android_bluetooth_hid(JNIEnv* env)
    515 {
    516     return jniRegisterNativeMethods(env, "com/android/bluetooth/hid/HidService",
    517                                     sMethods, NELEM(sMethods));
    518 }
    519 
    520 }
    521