com_android_bluetooth_hid.cpp revision 89d2a16ff98d1b6254139e1589404161d5c419c7
135207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie/*
235207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie * Copyright (C) 2012 Google Inc.
335207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie */
435207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
535207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie#define LOG_TAG "BluetoothHidServiceJni"
635207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
735207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie#define LOG_NDEBUG 0
835207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
935207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie#define CHECK_CALLBACK_ENV                                                      \
1035207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie   if (!checkCallbackThread()) {                                                \
1135207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie       LOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);\
1235207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie       return;                                                                  \
1335207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie   }
1435207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
1535207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie#include "com_android_bluetooth.h"
1635207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie#include "hardware/bt_hh.h"
1735207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie#include "utils/Log.h"
1835207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie#include "android_runtime/AndroidRuntime.h"
1935207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
2035207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie#include <string.h>
2135207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
2235207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xienamespace android {
2335207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
2435207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xiestatic jmethodID method_onConnectStateChanged;
2535207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
2635207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xiestatic const bthh_interface_t *sBluetoothHidInterface = NULL;
2735207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xiestatic jobject mCallbacksObj = NULL;
2835207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xiestatic JNIEnv *sCallbackEnv = NULL;
2935207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
3035207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xiestatic bool checkCallbackThread() {
3189d2a16ff98d1b6254139e1589404161d5c419c7Priti Aghera
3289d2a16ff98d1b6254139e1589404161d5c419c7Priti Aghera    // Always fetch the latest callbackEnv from AdapterService.
3389d2a16ff98d1b6254139e1589404161d5c419c7Priti Aghera    // Caching this could cause this sCallbackEnv to go out-of-sync
3489d2a16ff98d1b6254139e1589404161d5c419c7Priti Aghera    // with the AdapterService's ENV if an ASSOCIATE/DISASSOCIATE event
3589d2a16ff98d1b6254139e1589404161d5c419c7Priti Aghera    // is received
3689d2a16ff98d1b6254139e1589404161d5c419c7Priti Aghera
3789d2a16ff98d1b6254139e1589404161d5c419c7Priti Aghera    sCallbackEnv = getCallbackEnv();
3835207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
3935207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    JNIEnv* env = AndroidRuntime::getJNIEnv();
4035207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    if (sCallbackEnv != env || sCallbackEnv == NULL) return false;
4135207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    return true;
4235207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie}
4335207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
4435207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xiestatic void connection_state_callback(bt_bdaddr_t *bd_addr, bthh_connection_state_t state) {
4535207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    jbyteArray addr;
4635207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
4735207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    CHECK_CALLBACK_ENV
4835207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
4935207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    if (!addr) {
5035207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie        LOGE("Fail to new jbyteArray bd addr for HID channel state");
5135207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie        checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
5235207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie        return;
5335207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    }
5435207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
5535207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
5635207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectStateChanged, addr, (jint) state);
5735207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
5835207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    sCallbackEnv->DeleteLocalRef(addr);
5935207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie}
6035207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
6135207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xiestatic bthh_callbacks_t sBluetoothHidCallbacks = {
6235207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    sizeof(sBluetoothHidCallbacks),
6335207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    connection_state_callback,
6435207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    NULL,
6535207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    NULL,
6635207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    NULL,
6735207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    NULL,
6835207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    NULL
6935207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie};
7035207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
7135207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie// Define native functions
7235207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
7335207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xiestatic void classInitNative(JNIEnv* env, jclass clazz) {
7435207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    int err;
7535207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    const bt_interface_t* btInf;
7635207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    bt_status_t status;
7735207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
7835207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    method_onConnectStateChanged = env->GetMethodID(clazz, "onConnectStateChanged",
7935207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie                                                    "([BI)V");
8035207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
8135207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    if ( (btInf = getBluetoothInterface()) == NULL) {
8235207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie        LOGE("Bluetooth module is not loaded");
8335207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie        return;
8435207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    }
8535207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
8635207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    if ( (sBluetoothHidInterface = (bthh_interface_t *)
8735207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie          btInf->get_profile_interface(BT_PROFILE_HIDHOST_ID)) == NULL) {
8835207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie        LOGE("Failed to get Bluetooth Handsfree Interface");
8935207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie        return;
9035207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    }
9135207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
9235207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    // TODO(BT) do this only once or
9335207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    //          Do we need to do this every time the BT reenables?
9435207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    if ( (status = sBluetoothHidInterface->init(&sBluetoothHidCallbacks)) != BT_STATUS_SUCCESS) {
9535207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie        LOGE("Failed to initialize Bluetooth HID, status: %d", status);
9635207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie        sBluetoothHidInterface = NULL;
9735207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie        return;
9835207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    }
9935207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
10035207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    LOGI("%s: succeeds", __FUNCTION__);
10135207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie}
10235207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
10335207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xiestatic void initializeNativeDataNative(JNIEnv *env, jobject object) {
10435207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    // TODO(BT) clean it up when hid service is stopped
10535207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    mCallbacksObj = env->NewGlobalRef(object);
10635207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie}
10735207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
10835207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xiestatic jboolean connectHidNative(JNIEnv *env, jobject object, jbyteArray address) {
10935207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    bt_status_t status;
11035207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    jbyte *addr;
11135207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    jboolean ret = JNI_TRUE;
11235207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    if (!sBluetoothHidInterface) return JNI_FALSE;
11335207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
11435207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    addr = env->GetByteArrayElements(address, NULL);
11535207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    if (!addr) {
11635207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie        LOGE("Bluetooth device address null");
11735207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie        return JNI_FALSE;
11835207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    }
11935207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
12035207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    if ((status = sBluetoothHidInterface->connect((bt_bdaddr_t *) addr)) !=
12135207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie         BT_STATUS_SUCCESS) {
12235207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie        LOGE("Failed HID channel connection, status: %d", status);
12335207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie        ret = JNI_FALSE;
12435207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    }
12535207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    env->ReleaseByteArrayElements(address, addr, 0);
12635207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
12735207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    return ret;
12835207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie}
12935207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
13035207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xiestatic jboolean disconnectHidNative(JNIEnv *env, jobject object, jbyteArray address) {
13135207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    bt_status_t status;
13235207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    jbyte *addr;
13335207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    jboolean ret = JNI_TRUE;
13435207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    if (!sBluetoothHidInterface) return JNI_FALSE;
13535207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
13635207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    addr = env->GetByteArrayElements(address, NULL);
13735207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    if (!addr) {
13835207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie        LOGE("Bluetooth device address null");
13935207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie        return JNI_FALSE;
14035207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    }
14135207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
14235207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    if ( (status = sBluetoothHidInterface->disconnect((bt_bdaddr_t *) addr)) !=
14335207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie         BT_STATUS_SUCCESS) {
14435207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie        LOGE("Failed disconnect hid channel, status: %d", status);
14535207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie        ret = JNI_FALSE;
14635207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    }
14735207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    env->ReleaseByteArrayElements(address, addr, 0);
14835207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
14935207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    return ret;
15035207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie}
15135207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
15235207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xiestatic JNINativeMethod sMethods[] = {
15335207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    {"classInitNative", "()V", (void *) classInitNative},
15435207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    {"initializeNativeDataNative", "()V", (void *) initializeNativeDataNative},
15535207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    {"connectHidNative", "([B)Z", (void *) connectHidNative},
15635207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    {"disconnectHidNative", "([B)Z", (void *) disconnectHidNative},
15735207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    // TBD
15835207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie};
15935207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
16035207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xieint register_com_android_bluetooth_hid(JNIEnv* env)
16135207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie{
16235207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie    return jniRegisterNativeMethods(env, "com/android/bluetooth/hid/HidService",
16335207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie                                    sMethods, NELEM(sMethods));
16435207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie}
16535207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie
16635207a5638f61caca5b9abb31e5c6850a9478a52Matthew Xie}
167