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 "BluetoothAvrcpControllerJni"
     18 
     19 #define LOG_NDEBUG 0
     20 
     21 #include "com_android_bluetooth.h"
     22 #include "hardware/bt_rc.h"
     23 #include "utils/Log.h"
     24 #include "android_runtime/AndroidRuntime.h"
     25 
     26 #include <string.h>
     27 
     28 namespace android {
     29 static jmethodID method_handlePassthroughRsp;
     30 static jmethodID method_onConnectionStateChanged;
     31 
     32 static const btrc_ctrl_interface_t *sBluetoothAvrcpInterface = NULL;
     33 static jobject mCallbacksObj = NULL;
     34 static JNIEnv *sCallbackEnv = NULL;
     35 
     36 static bool checkCallbackThread() {
     37     // Always fetch the latest callbackEnv from AdapterService.
     38     // Caching this could cause this sCallbackEnv to go out-of-sync
     39     // with the AdapterService's ENV if an ASSOCIATE/DISASSOCIATE event
     40     // is received
     41     sCallbackEnv = getCallbackEnv();
     42 
     43     JNIEnv* env = AndroidRuntime::getJNIEnv();
     44     if (sCallbackEnv != env || sCallbackEnv == NULL) return false;
     45     return true;
     46 }
     47 
     48 static void btavrcp_passthrough_response_callback(int id, int pressed) {
     49     ALOGI("%s", __FUNCTION__);
     50     ALOGI("id: %d, pressed: %d", id, pressed);
     51 
     52     if (!checkCallbackThread()) {
     53         ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
     54         return;
     55     }
     56 
     57     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handlePassthroughRsp, (jint)id,
     58                                                                              (jint)pressed);
     59     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
     60 }
     61 
     62 static void btavrcp_connection_state_callback(bool state, bt_bdaddr_t* bd_addr) {
     63     jbyteArray addr;
     64 
     65     ALOGI("%s", __FUNCTION__);
     66     ALOGI("conn state: %d", state);
     67 
     68     if (!checkCallbackThread()) {                                       \
     69         ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \
     70         return;                                                         \
     71     }
     72 
     73     addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
     74     if (!addr) {
     75         ALOGE("Fail to new jbyteArray bd addr for connection state");
     76         checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
     77         return;
     78     }
     79 
     80     sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
     81     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged, (jboolean) state,
     82                                  addr);
     83     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
     84     sCallbackEnv->DeleteLocalRef(addr);
     85 }
     86 
     87 
     88 static btrc_ctrl_callbacks_t sBluetoothAvrcpCallbacks = {
     89     sizeof(sBluetoothAvrcpCallbacks),
     90     btavrcp_passthrough_response_callback,
     91     btavrcp_connection_state_callback
     92 };
     93 
     94 static void classInitNative(JNIEnv* env, jclass clazz) {
     95     method_handlePassthroughRsp =
     96         env->GetMethodID(clazz, "handlePassthroughRsp", "(II)V");
     97 
     98     method_onConnectionStateChanged =
     99         env->GetMethodID(clazz, "onConnectionStateChanged", "(Z[B)V");
    100 
    101     ALOGI("%s: succeeds", __FUNCTION__);
    102 }
    103 
    104 static void initNative(JNIEnv *env, jobject object) {
    105     const bt_interface_t* btInf;
    106     bt_status_t status;
    107 
    108     if ( (btInf = getBluetoothInterface()) == NULL) {
    109         ALOGE("Bluetooth module is not loaded");
    110         return;
    111     }
    112 
    113     if (sBluetoothAvrcpInterface !=NULL) {
    114          ALOGW("Cleaning up Avrcp Interface before initializing...");
    115          sBluetoothAvrcpInterface->cleanup();
    116          sBluetoothAvrcpInterface = NULL;
    117     }
    118 
    119     if (mCallbacksObj != NULL) {
    120          ALOGW("Cleaning up Avrcp callback object");
    121          env->DeleteGlobalRef(mCallbacksObj);
    122          mCallbacksObj = NULL;
    123     }
    124 
    125     if ( (sBluetoothAvrcpInterface = (btrc_ctrl_interface_t *)
    126           btInf->get_profile_interface(BT_PROFILE_AV_RC_CTRL_ID)) == NULL) {
    127         ALOGE("Failed to get Bluetooth Avrcp Controller Interface");
    128         return;
    129     }
    130 
    131     if ( (status = sBluetoothAvrcpInterface->init(&sBluetoothAvrcpCallbacks)) !=
    132          BT_STATUS_SUCCESS) {
    133         ALOGE("Failed to initialize Bluetooth Avrcp Controller, status: %d", status);
    134         sBluetoothAvrcpInterface = NULL;
    135         return;
    136     }
    137 
    138     mCallbacksObj = env->NewGlobalRef(object);
    139 }
    140 
    141 static void cleanupNative(JNIEnv *env, jobject object) {
    142     const bt_interface_t* btInf;
    143 
    144     if ( (btInf = getBluetoothInterface()) == NULL) {
    145         ALOGE("Bluetooth module is not loaded");
    146         return;
    147     }
    148 
    149     if (sBluetoothAvrcpInterface !=NULL) {
    150         sBluetoothAvrcpInterface->cleanup();
    151         sBluetoothAvrcpInterface = NULL;
    152     }
    153 
    154     if (mCallbacksObj != NULL) {
    155         env->DeleteGlobalRef(mCallbacksObj);
    156         mCallbacksObj = NULL;
    157     }
    158 }
    159 
    160 static jboolean sendPassThroughCommandNative(JNIEnv *env, jobject object, jbyteArray address,
    161                                                     jint key_code, jint key_state) {
    162     jbyte *addr;
    163     bt_status_t status;
    164 
    165     if (!sBluetoothAvrcpInterface) return JNI_FALSE;
    166 
    167     ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
    168 
    169     ALOGI("key_code: %d, key_state: %d", key_code, key_state);
    170 
    171     addr = env->GetByteArrayElements(address, NULL);
    172     if (!addr) {
    173         jniThrowIOException(env, EINVAL);
    174         return JNI_FALSE;
    175     }
    176 
    177     if ((status = sBluetoothAvrcpInterface->send_pass_through_cmd((bt_bdaddr_t *)addr,
    178             (uint8_t)key_code, (uint8_t)key_state))!= BT_STATUS_SUCCESS) {
    179         ALOGE("Failed sending passthru command, status: %d", status);
    180     }
    181     env->ReleaseByteArrayElements(address, addr, 0);
    182 
    183     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    184 }
    185 
    186 static JNINativeMethod sMethods[] = {
    187     {"classInitNative", "()V", (void *) classInitNative},
    188     {"initNative", "()V", (void *) initNative},
    189     {"cleanupNative", "()V", (void *) cleanupNative},
    190     {"sendPassThroughCommandNative", "([BII)Z",
    191      (void *) sendPassThroughCommandNative},
    192 };
    193 
    194 int register_com_android_bluetooth_avrcp_controller(JNIEnv* env)
    195 {
    196     return jniRegisterNativeMethods(env, "com/android/bluetooth/avrcp/AvrcpControllerService",
    197                                     sMethods, NELEM(sMethods));
    198 }
    199 
    200 }
    201