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
checkCallbackThread()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
btavrcp_passthrough_response_callback(int id,int pressed)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
btavrcp_connection_state_callback(bool state,bt_bdaddr_t * bd_addr)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
classInitNative(JNIEnv * env,jclass clazz)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
initNative(JNIEnv * env,jobject object)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
cleanupNative(JNIEnv * env,jobject object)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
sendPassThroughCommandNative(JNIEnv * env,jobject object,jbyteArray address,jint key_code,jint key_state)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
register_com_android_bluetooth_avrcp_controller(JNIEnv * env)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