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
28namespace android {
29static jmethodID method_handlePassthroughRsp;
30static jmethodID method_onConnectionStateChanged;
31static jmethodID method_getRcFeatures;
32static jmethodID method_setplayerappsettingrsp;
33static jmethodID method_handleplayerappsetting;
34static jmethodID method_handleplayerappsettingchanged;
35static jmethodID method_handleSetAbsVolume;
36static jmethodID method_handleRegisterNotificationAbsVol;
37static jmethodID method_handletrackchanged;
38static jmethodID method_handleplaypositionchanged;
39static jmethodID method_handleplaystatuschanged;
40static jmethodID method_handleGroupNavigationRsp;
41
42
43static const btrc_ctrl_interface_t *sBluetoothAvrcpInterface = NULL;
44static jobject mCallbacksObj = NULL;
45static JNIEnv *sCallbackEnv = NULL;
46
47static 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
59static 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
73static 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
86static 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
111static 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
134static 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
158static 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
215static 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
262static 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
287static 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
311static 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
379static 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
397static 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
414static 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
430static 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
469static 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
506static 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
525static 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
551static 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
577static 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
635static 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
655static 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
675static 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
687int 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