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