• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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