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 static jmethodID method_getRcFeatures;
32 static jmethodID method_setplayerappsettingrsp;
33 static jmethodID method_handleplayerappsetting;
34 static jmethodID method_handleplayerappsettingchanged;
35 static jmethodID method_handleSetAbsVolume;
36 static jmethodID method_handleRegisterNotificationAbsVol;
37 static jmethodID method_handletrackchanged;
38 static jmethodID method_handleplaypositionchanged;
39 static jmethodID method_handleplaystatuschanged;
40 static jmethodID method_handleGroupNavigationRsp;
41
42
43 static const btrc_ctrl_interface_t *sBluetoothAvrcpInterface = NULL;
44 static jobject mCallbacksObj = NULL;
45 static JNIEnv *sCallbackEnv = NULL;
46
checkCallbackThread()47 static bool checkCallbackThread() {
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 sCallbackEnv = getCallbackEnv();
53
54 JNIEnv* env = AndroidRuntime::getJNIEnv();
55 if (sCallbackEnv != env || sCallbackEnv == NULL) return false;
56 return true;
57 }
58
btavrcp_passthrough_response_callback(int id,int pressed)59 static void btavrcp_passthrough_response_callback(int id, int pressed) {
60 ALOGI("%s", __FUNCTION__);
61 ALOGI("id: %d, pressed: %d", id, pressed);
62
63 if (!checkCallbackThread()) {
64 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
65 return;
66 }
67
68 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handlePassthroughRsp, (jint)id,
69 (jint)pressed);
70 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
71 }
72
btavrcp_groupnavigation_response_callback(int id,int pressed)73 static void btavrcp_groupnavigation_response_callback(int id, int pressed) {
74 ALOGI("%s", __FUNCTION__);
75
76 if (!checkCallbackThread()) {
77 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
78 return;
79 }
80
81 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handleGroupNavigationRsp, (jint)id,
82 (jint)pressed);
83 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
84 }
85
btavrcp_connection_state_callback(bool state,bt_bdaddr_t * bd_addr)86 static void btavrcp_connection_state_callback(bool state, bt_bdaddr_t* bd_addr) {
87 jbyteArray addr;
88
89 ALOGI("%s", __FUNCTION__);
90 ALOGI("conn state: %d", state);
91
92 if (!checkCallbackThread()) { \
93 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \
94 return; \
95 }
96
97 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
98 if (!addr) {
99 ALOGE("Fail to new jbyteArray bd addr for connection state");
100 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
101 return;
102 }
103
104 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
105 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged, (jboolean) state,
106 addr);
107 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
108 sCallbackEnv->DeleteLocalRef(addr);
109 }
110
btavrcp_get_rcfeatures_callback(bt_bdaddr_t * bd_addr,int features)111 static void btavrcp_get_rcfeatures_callback(bt_bdaddr_t *bd_addr, int features) {
112 jbyteArray addr;
113
114 ALOGI("%s", __FUNCTION__);
115
116 if (!checkCallbackThread()) { \
117 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \
118 return; \
119 }
120
121 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
122 if (!addr) {
123 ALOGE("Fail to new jbyteArray bd addr ");
124 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
125 return;
126 }
127
128 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
129 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getRcFeatures, addr, (jint)features);
130 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
131 sCallbackEnv->DeleteLocalRef(addr);
132 }
133
btavrcp_setplayerapplicationsetting_rsp_callback(bt_bdaddr_t * bd_addr,uint8_t accepted)134 static void btavrcp_setplayerapplicationsetting_rsp_callback(bt_bdaddr_t *bd_addr,
135 uint8_t accepted) {
136 jbyteArray addr;
137
138 ALOGI("%s", __FUNCTION__);
139
140 if (!checkCallbackThread()) { \
141 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \
142 return; \
143 }
144
145 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
146 if (!addr) {
147 ALOGE("Fail to new jbyteArray bd addr ");
148 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
149 return;
150 }
151
152 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
153 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_setplayerappsettingrsp, addr, (jint)accepted);
154 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
155 sCallbackEnv->DeleteLocalRef(addr);
156 }
157
btavrcp_playerapplicationsetting_callback(bt_bdaddr_t * bd_addr,uint8_t num_attr,btrc_player_app_attr_t * app_attrs,uint8_t num_ext_attr,btrc_player_app_ext_attr_t * ext_attrs)158 static void btavrcp_playerapplicationsetting_callback(bt_bdaddr_t *bd_addr, uint8_t num_attr,
159 btrc_player_app_attr_t *app_attrs, uint8_t num_ext_attr,
160 btrc_player_app_ext_attr_t *ext_attrs) {
161 ALOGI("%s", __FUNCTION__);
162 jbyteArray addr;
163 jbyteArray playerattribs;
164 jint arraylen;
165 int i,k;
166
167 if (!checkCallbackThread()) { \
168 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \
169 return; \
170 }
171
172 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
173 if (!addr) {
174 ALOGE("Fail to new jbyteArray bd addr ");
175 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
176 return;
177 }
178 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*)bd_addr);
179 /* TODO ext attrs
180 * Flattening defined attributes: <id,num_values,values[]>
181 */
182 arraylen = 0;
183 for (i = 0; i < num_attr; i++)
184 {
185 /*2 bytes for id and num */
186 arraylen += 2 + app_attrs[i].num_val;
187 }
188 ALOGI(" arraylen %d", arraylen);
189 playerattribs = sCallbackEnv->NewByteArray(arraylen);
190 if(!playerattribs)
191 {
192 ALOGE("Fail to new jbyteArray playerattribs ");
193 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
194 sCallbackEnv->DeleteLocalRef(addr);
195 return;
196 }
197 k= 0;
198 for (i = 0; (i < num_attr)&&(k < arraylen); i++)
199 {
200 sCallbackEnv->SetByteArrayRegion(playerattribs, k, 1, (jbyte*)&(app_attrs[i].attr_id));
201 k++;
202 sCallbackEnv->SetByteArrayRegion(playerattribs, k, 1, (jbyte*)&(app_attrs[i].num_val));
203 k++;
204 sCallbackEnv->SetByteArrayRegion(playerattribs, k, app_attrs[i].num_val,
205 (jbyte*)(app_attrs[i].attr_val));
206 k = k + app_attrs[i].num_val;
207 }
208 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handleplayerappsetting, addr,
209 playerattribs, (jint)arraylen);
210 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
211 sCallbackEnv->DeleteLocalRef(addr);
212 sCallbackEnv->DeleteLocalRef(playerattribs);
213 }
214
btavrcp_playerapplicationsetting_changed_callback(bt_bdaddr_t * bd_addr,btrc_player_settings_t * p_vals)215 static void btavrcp_playerapplicationsetting_changed_callback(bt_bdaddr_t *bd_addr,
216 btrc_player_settings_t *p_vals) {
217
218 jbyteArray addr;
219 jbyteArray playerattribs;
220 int i, k, arraylen;
221 ALOGI("%s", __FUNCTION__);
222
223 if (!checkCallbackThread()) { \
224 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \
225 return; \
226 }
227
228 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
229 if ((!addr)) {
230 ALOGE("Fail to get new array ");
231 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
232 return;
233 }
234 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*)bd_addr);
235 arraylen = p_vals->num_attr*2;
236 playerattribs = sCallbackEnv->NewByteArray(arraylen);
237 if(!playerattribs)
238 {
239 ALOGE("Fail to new jbyteArray playerattribs ");
240 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
241 sCallbackEnv->DeleteLocalRef(addr);
242 return;
243 }
244 /*
245 * Flatening format: <id,val>
246 */
247 k = 0;
248 for (i = 0; (i < p_vals->num_attr)&&( k < arraylen);i++)
249 {
250 sCallbackEnv->SetByteArrayRegion(playerattribs, k, 1, (jbyte*)&(p_vals->attr_ids[i]));
251 k++;
252 sCallbackEnv->SetByteArrayRegion(playerattribs, k, 1, (jbyte*)&(p_vals->attr_values[i]));
253 k++;
254 }
255 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handleplayerappsettingchanged, addr,
256 playerattribs, (jint)arraylen);
257 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
258 sCallbackEnv->DeleteLocalRef(addr);
259 sCallbackEnv->DeleteLocalRef(playerattribs);
260 }
261
btavrcp_set_abs_vol_cmd_callback(bt_bdaddr_t * bd_addr,uint8_t abs_vol,uint8_t label)262 static void btavrcp_set_abs_vol_cmd_callback(bt_bdaddr_t *bd_addr, uint8_t abs_vol,
263 uint8_t label) {
264
265 jbyteArray addr;
266 ALOGI("%s", __FUNCTION__);
267
268 if (!checkCallbackThread()) { \
269 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \
270 return; \
271 }
272
273 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
274 if ((!addr)) {
275 ALOGE("Fail to get new array ");
276 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
277 return;
278 }
279
280 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*)bd_addr);
281 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handleSetAbsVolume, addr, (jbyte)abs_vol,
282 (jbyte)label);
283 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
284 sCallbackEnv->DeleteLocalRef(addr);
285 }
286
btavrcp_register_notification_absvol_callback(bt_bdaddr_t * bd_addr,uint8_t label)287 static void btavrcp_register_notification_absvol_callback(bt_bdaddr_t *bd_addr, uint8_t label) {
288 jbyteArray addr;
289
290 ALOGI("%s", __FUNCTION__);
291
292 if (!checkCallbackThread()) { \
293 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \
294 return; \
295 }
296
297 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
298 if ((!addr)) {
299 ALOGE("Fail to get new array ");
300 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
301 return;
302 }
303
304 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*)bd_addr);
305 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handleRegisterNotificationAbsVol, addr,
306 (jbyte)label);
307 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
308 sCallbackEnv->DeleteLocalRef(addr);
309 }
310
btavrcp_track_changed_callback(bt_bdaddr_t * bd_addr,uint8_t num_attr,btrc_element_attr_val_t * p_attrs)311 static void btavrcp_track_changed_callback(bt_bdaddr_t *bd_addr, uint8_t num_attr,
312 btrc_element_attr_val_t *p_attrs) {
313 /*
314 * byteArray will be formatted like this: id,len,string
315 * Assuming text feild to be null terminated.
316 */
317 jbyteArray addr;
318 jintArray attribIds;
319 jobjectArray stringArray;
320 jstring str;
321 jclass strclazz;
322 jint i;
323 ALOGI("%s", __FUNCTION__);
324 if (!checkCallbackThread()) { \
325 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \
326 return; \
327 }
328
329 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
330 if ((!addr)) {
331 ALOGE("Fail to get new array ");
332 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
333 return;
334 }
335 attribIds = sCallbackEnv->NewIntArray(num_attr);
336 if(!attribIds) {
337 ALOGE(" failed to set new array for attribIds");
338 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
339 sCallbackEnv->DeleteLocalRef(addr);
340 return;
341 }
342 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*)bd_addr);
343
344 strclazz = sCallbackEnv->FindClass("java/lang/String");
345 stringArray = sCallbackEnv->NewObjectArray((jint)num_attr, strclazz, 0);
346 if(!stringArray) {
347 ALOGE(" failed to get String array");
348 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
349 sCallbackEnv->DeleteLocalRef(addr);
350 sCallbackEnv->DeleteLocalRef(attribIds);
351 return;
352 }
353 for(i = 0; i < num_attr; i++)
354 {
355 str = sCallbackEnv->NewStringUTF((char*)(p_attrs[i].text));
356 if(!str) {
357 ALOGE(" Unable to get str ");
358 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
359 sCallbackEnv->DeleteLocalRef(addr);
360 sCallbackEnv->DeleteLocalRef(attribIds);
361 sCallbackEnv->DeleteLocalRef(stringArray);
362 return;
363 }
364 sCallbackEnv->SetIntArrayRegion(attribIds, i, 1, (jint*)&(p_attrs[i].attr_id));
365 sCallbackEnv->SetObjectArrayElement(stringArray, i,str);
366 sCallbackEnv->DeleteLocalRef(str);
367 }
368
369 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handletrackchanged, addr,
370 (jbyte)(num_attr), attribIds, stringArray);
371 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
372 sCallbackEnv->DeleteLocalRef(addr);
373 sCallbackEnv->DeleteLocalRef(attribIds);
374 /* TODO check do we need to delete str seperately or not */
375 sCallbackEnv->DeleteLocalRef(stringArray);
376 sCallbackEnv->DeleteLocalRef(strclazz);
377 }
378
btavrcp_play_position_changed_callback(bt_bdaddr_t * bd_addr,uint32_t song_len,uint32_t song_pos)379 static void btavrcp_play_position_changed_callback(bt_bdaddr_t *bd_addr, uint32_t song_len,
380 uint32_t song_pos) {
381
382 jbyteArray addr;
383 ALOGI("%s", __FUNCTION__);
384
385 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
386 if ((!addr)) {
387 ALOGE("Fail to get new array ");
388 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
389 return;
390 }
391 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
392 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handleplaypositionchanged, addr,
393 (jint)(song_len), (jint)song_pos);
394 sCallbackEnv->DeleteLocalRef(addr);
395 }
396
btavrcp_play_status_changed_callback(bt_bdaddr_t * bd_addr,btrc_play_status_t play_status)397 static void btavrcp_play_status_changed_callback(bt_bdaddr_t *bd_addr,
398 btrc_play_status_t play_status) {
399 jbyteArray addr;
400 ALOGI("%s", __FUNCTION__);
401
402 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
403 if ((!addr)) {
404 ALOGE("Fail to get new array ");
405 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
406 return;
407 }
408 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
409 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handleplaystatuschanged, addr,
410 (jbyte)play_status);
411 sCallbackEnv->DeleteLocalRef(addr);
412 }
413
414 static btrc_ctrl_callbacks_t sBluetoothAvrcpCallbacks = {
415 sizeof(sBluetoothAvrcpCallbacks),
416 btavrcp_passthrough_response_callback,
417 btavrcp_groupnavigation_response_callback,
418 btavrcp_connection_state_callback,
419 btavrcp_get_rcfeatures_callback,
420 btavrcp_setplayerapplicationsetting_rsp_callback,
421 btavrcp_playerapplicationsetting_callback,
422 btavrcp_playerapplicationsetting_changed_callback,
423 btavrcp_set_abs_vol_cmd_callback,
424 btavrcp_register_notification_absvol_callback,
425 btavrcp_track_changed_callback,
426 btavrcp_play_position_changed_callback,
427 btavrcp_play_status_changed_callback
428 };
429
classInitNative(JNIEnv * env,jclass clazz)430 static void classInitNative(JNIEnv* env, jclass clazz) {
431 method_handlePassthroughRsp =
432 env->GetMethodID(clazz, "handlePassthroughRsp", "(II)V");
433
434 method_handleGroupNavigationRsp =
435 env->GetMethodID(clazz, "handleGroupNavigationRsp", "(II)V");
436
437 method_onConnectionStateChanged =
438 env->GetMethodID(clazz, "onConnectionStateChanged", "(Z[B)V");
439
440 method_getRcFeatures =
441 env->GetMethodID(clazz, "getRcFeatures", "([BI)V");
442
443 method_setplayerappsettingrsp =
444 env->GetMethodID(clazz, "setPlayerAppSettingRsp", "([BB)V");
445
446 method_handleplayerappsetting =
447 env->GetMethodID(clazz, "handlePlayerAppSetting", "([B[BI)V");
448
449 method_handleplayerappsettingchanged =
450 env->GetMethodID(clazz, "onPlayerAppSettingChanged", "([B[BI)V");
451
452 method_handleSetAbsVolume =
453 env->GetMethodID(clazz, "handleSetAbsVolume", "([BBB)V");
454
455 method_handleRegisterNotificationAbsVol =
456 env->GetMethodID(clazz, "handleRegisterNotificationAbsVol", "([BB)V");
457
458 method_handletrackchanged =
459 env->GetMethodID(clazz, "onTrackChanged", "([BB[I[Ljava/lang/String;)V");
460
461 method_handleplaypositionchanged =
462 env->GetMethodID(clazz, "onPlayPositionChanged", "([BII)V");
463
464 method_handleplaystatuschanged =
465 env->GetMethodID(clazz, "onPlayStatusChanged", "([BB)V");
466 ALOGI("%s: succeeds", __FUNCTION__);
467 }
468
initNative(JNIEnv * env,jobject object)469 static void initNative(JNIEnv *env, jobject object) {
470 const bt_interface_t* btInf;
471 bt_status_t status;
472
473 if ( (btInf = getBluetoothInterface()) == NULL) {
474 ALOGE("Bluetooth module is not loaded");
475 return;
476 }
477
478 if (sBluetoothAvrcpInterface !=NULL) {
479 ALOGW("Cleaning up Avrcp Interface before initializing...");
480 sBluetoothAvrcpInterface->cleanup();
481 sBluetoothAvrcpInterface = NULL;
482 }
483
484 if (mCallbacksObj != NULL) {
485 ALOGW("Cleaning up Avrcp callback object");
486 env->DeleteGlobalRef(mCallbacksObj);
487 mCallbacksObj = NULL;
488 }
489
490 if ( (sBluetoothAvrcpInterface = (btrc_ctrl_interface_t *)
491 btInf->get_profile_interface(BT_PROFILE_AV_RC_CTRL_ID)) == NULL) {
492 ALOGE("Failed to get Bluetooth Avrcp Controller Interface");
493 return;
494 }
495
496 if ( (status = sBluetoothAvrcpInterface->init(&sBluetoothAvrcpCallbacks)) !=
497 BT_STATUS_SUCCESS) {
498 ALOGE("Failed to initialize Bluetooth Avrcp Controller, status: %d", status);
499 sBluetoothAvrcpInterface = NULL;
500 return;
501 }
502
503 mCallbacksObj = env->NewGlobalRef(object);
504 }
505
cleanupNative(JNIEnv * env,jobject object)506 static void cleanupNative(JNIEnv *env, jobject object) {
507 const bt_interface_t* btInf;
508
509 if ( (btInf = getBluetoothInterface()) == NULL) {
510 ALOGE("Bluetooth module is not loaded");
511 return;
512 }
513
514 if (sBluetoothAvrcpInterface !=NULL) {
515 sBluetoothAvrcpInterface->cleanup();
516 sBluetoothAvrcpInterface = NULL;
517 }
518
519 if (mCallbacksObj != NULL) {
520 env->DeleteGlobalRef(mCallbacksObj);
521 mCallbacksObj = NULL;
522 }
523 }
524
sendPassThroughCommandNative(JNIEnv * env,jobject object,jbyteArray address,jint key_code,jint key_state)525 static jboolean sendPassThroughCommandNative(JNIEnv *env, jobject object, jbyteArray address,
526 jint key_code, jint key_state) {
527 jbyte *addr;
528 bt_status_t status;
529
530 if (!sBluetoothAvrcpInterface) return JNI_FALSE;
531
532 ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
533
534 ALOGI("key_code: %d, key_state: %d", key_code, key_state);
535
536 addr = env->GetByteArrayElements(address, NULL);
537 if (!addr) {
538 jniThrowIOException(env, EINVAL);
539 return JNI_FALSE;
540 }
541
542 if ((status = sBluetoothAvrcpInterface->send_pass_through_cmd((bt_bdaddr_t *)addr,
543 (uint8_t)key_code, (uint8_t)key_state))!= BT_STATUS_SUCCESS) {
544 ALOGE("Failed sending passthru command, status: %d", status);
545 }
546 env->ReleaseByteArrayElements(address, addr, 0);
547
548 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
549 }
550
sendGroupNavigationCommandNative(JNIEnv * env,jobject object,jbyteArray address,jint key_code,jint key_state)551 static jboolean sendGroupNavigationCommandNative(JNIEnv *env, jobject object, jbyteArray address,
552 jint key_code, jint key_state) {
553 jbyte *addr;
554 bt_status_t status;
555
556 if (!sBluetoothAvrcpInterface) return JNI_FALSE;
557
558 ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
559
560 ALOGI("key_code: %d, key_state: %d", key_code, key_state);
561
562 addr = env->GetByteArrayElements(address, NULL);
563 if (!addr) {
564 jniThrowIOException(env, EINVAL);
565 return JNI_FALSE;
566 }
567
568 if ((status = sBluetoothAvrcpInterface->send_group_navigation_cmd((bt_bdaddr_t *)addr,
569 (uint8_t)key_code, (uint8_t)key_state))!= BT_STATUS_SUCCESS) {
570 ALOGE("Failed sending Grp Navigation command, status: %d", status);
571 }
572 env->ReleaseByteArrayElements(address, addr, 0);
573
574 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
575 }
576
setPlayerApplicationSettingValuesNative(JNIEnv * env,jobject object,jbyteArray address,jbyte num_attrib,jbyteArray attrib_ids,jbyteArray attrib_val)577 static void setPlayerApplicationSettingValuesNative(JNIEnv *env, jobject object, jbyteArray address,
578 jbyte num_attrib, jbyteArray attrib_ids,
579 jbyteArray attrib_val) {
580 bt_status_t status;
581 jbyte *addr;
582 uint8_t *pAttrs = NULL;
583 uint8_t *pAttrsVal = NULL;
584 int i;
585 jbyte *attr;
586 jbyte *attr_val;
587
588 if (!sBluetoothAvrcpInterface) return;
589
590 addr = env->GetByteArrayElements(address, NULL);
591 if (!addr) {
592 jniThrowIOException(env, EINVAL);
593 return;
594 }
595
596 pAttrs = new uint8_t[num_attrib];
597 pAttrsVal = new uint8_t[num_attrib];
598 if ((!pAttrs) ||(!pAttrsVal)) {
599 delete[] pAttrs;
600 ALOGE("setPlayerApplicationSettingValuesNative: not have enough memeory");
601 return;
602 }
603 attr = env->GetByteArrayElements(attrib_ids, NULL);
604 attr_val = env->GetByteArrayElements(attrib_val, NULL);
605 if ((!attr)||(!attr_val)) {
606 delete[] pAttrs;
607 delete[] pAttrsVal;
608 jniThrowIOException(env, EINVAL);
609 return;
610 }
611 for (i = 0; i < num_attrib; ++i) {
612 pAttrs[i] = (uint8_t)attr[i];
613 pAttrsVal[i] = (uint8_t)attr_val[i];
614 }
615 if (i < num_attrib) {
616 delete[] pAttrs;
617 delete[] pAttrsVal;
618 env->ReleaseByteArrayElements(attrib_ids, attr, 0);
619 env->ReleaseByteArrayElements(attrib_val, attr_val, 0);
620 return;
621 }
622
623 ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
624 if ((status = sBluetoothAvrcpInterface->set_player_app_setting_cmd((bt_bdaddr_t *)addr,
625 (uint8_t)num_attrib, pAttrs, pAttrsVal))!= BT_STATUS_SUCCESS) {
626 ALOGE("Failed sending setPlAppSettValNative command, status: %d", status);
627 }
628 delete[] pAttrs;
629 delete[] pAttrsVal;
630 env->ReleaseByteArrayElements(attrib_ids, attr, 0);
631 env->ReleaseByteArrayElements(attrib_val, attr_val, 0);
632 env->ReleaseByteArrayElements(address, addr, 0);
633 }
634
sendAbsVolRspNative(JNIEnv * env,jobject object,jbyteArray address,jint abs_vol,jint label)635 static void sendAbsVolRspNative(JNIEnv *env, jobject object, jbyteArray address,
636 jint abs_vol, jint label) {
637 bt_status_t status;
638 jbyte *addr;
639
640 if (!sBluetoothAvrcpInterface) return;
641 addr = env->GetByteArrayElements(address, NULL);
642 if (!addr) {
643 jniThrowIOException(env, EINVAL);
644 return;
645 }
646
647 ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
648 if ((status = sBluetoothAvrcpInterface->set_volume_rsp((bt_bdaddr_t *)addr,
649 (uint8_t)abs_vol, (uint8_t)label))!= BT_STATUS_SUCCESS) {
650 ALOGE("Failed sending sendAbsVolRspNative command, status: %d", status);
651 }
652 env->ReleaseByteArrayElements(address, addr, 0);
653 }
654
sendRegisterAbsVolRspNative(JNIEnv * env,jobject object,jbyteArray address,jbyte rsp_type,jint abs_vol,jint label)655 static void sendRegisterAbsVolRspNative(JNIEnv *env, jobject object, jbyteArray address,
656 jbyte rsp_type, jint abs_vol, jint label) {
657 bt_status_t status;
658 jbyte *addr;
659
660 if (!sBluetoothAvrcpInterface) return;
661 addr = env->GetByteArrayElements(address, NULL);
662 if (!addr) {
663 jniThrowIOException(env, EINVAL);
664 return;
665 }
666 ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
667 if ((status = sBluetoothAvrcpInterface->register_abs_vol_rsp((bt_bdaddr_t *)addr,
668 (btrc_notification_type_t)rsp_type,(uint8_t)abs_vol, (uint8_t)label))
669 != BT_STATUS_SUCCESS) {
670 ALOGE("Failed sending sendRegisterAbsVolRspNative command, status: %d", status);
671 }
672 env->ReleaseByteArrayElements(address, addr, 0);
673 }
674
675 static JNINativeMethod sMethods[] = {
676 {"classInitNative", "()V", (void *) classInitNative},
677 {"initNative", "()V", (void *) initNative},
678 {"cleanupNative", "()V", (void *) cleanupNative},
679 {"sendPassThroughCommandNative", "([BII)Z",(void *) sendPassThroughCommandNative},
680 {"sendGroupNavigationCommandNative", "([BII)Z",(void *) sendGroupNavigationCommandNative},
681 {"setPlayerApplicationSettingValuesNative", "([BB[B[B)V",
682 (void *) setPlayerApplicationSettingValuesNative},
683 {"sendAbsVolRspNative", "([BII)V",(void *) sendAbsVolRspNative},
684 {"sendRegisterAbsVolRspNative", "([BBII)V",(void *) sendRegisterAbsVolRspNative},
685 };
686
register_com_android_bluetooth_avrcp_controller(JNIEnv * env)687 int register_com_android_bluetooth_avrcp_controller(JNIEnv* env)
688 {
689 return jniRegisterNativeMethods(env, "com/android/bluetooth/avrcp/AvrcpControllerService",
690 sMethods, NELEM(sMethods));
691 }
692
693 }
694