com_android_bluetooth_avrcp.cpp revision aa1ffd5c6bd4f016c6ed452b3551e65872eaea8e
1c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu/*
2c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * Copyright (C) 2012 The Android Open Source Project
3c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu *
4c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * Licensed under the Apache License, Version 2.0 (the "License");
5c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * you may not use this file except in compliance with the License.
6c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * You may obtain a copy of the License at
7c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu *
8c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu *      http://www.apache.org/licenses/LICENSE-2.0
9c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu *
10c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * Unless required by applicable law or agreed to in writing, software
11c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * distributed under the License is distributed on an "AS IS" BASIS,
12c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * See the License for the specific language governing permissions and
14c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * limitations under the License.
15c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu */
16c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
17c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu#define LOG_TAG "BluetoothAvrcpServiceJni"
18c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
19c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu#define LOG_NDEBUG 0
20c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
21c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu#include "com_android_bluetooth.h"
22c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu#include "hardware/bt_rc.h"
23c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu#include "utils/Log.h"
24c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu#include "android_runtime/AndroidRuntime.h"
25c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
26c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu#include <string.h>
27c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
28c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xunamespace android {
29c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic jmethodID method_getPlayStatus;
30c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic jmethodID method_getElementAttr;
31c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic jmethodID method_registerNotification;
32c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
33c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic const btrc_interface_t *sBluetoothAvrcpInterface = NULL;
34c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic jobject mCallbacksObj = NULL;
35c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic JNIEnv *sCallbackEnv = NULL;
36c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
37c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic bool checkCallbackThread() {
38c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    // Always fetch the latest callbackEnv from AdapterService.
39c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    // Caching this could cause this sCallbackEnv to go out-of-sync
40c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    // with the AdapterService's ENV if an ASSOCIATE/DISASSOCIATE event
41c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    // is received
42c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    sCallbackEnv = getCallbackEnv();
43c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
44c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    JNIEnv* env = AndroidRuntime::getJNIEnv();
45c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (sCallbackEnv != env || sCallbackEnv == NULL) return false;
46c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    return true;
47c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
48c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
49c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic void btavrcp_get_play_status_callback() {
50c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    ALOGI("%s", __FUNCTION__);
51c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
52c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (!checkCallbackThread()) {
53c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
54c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return;
55c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
56c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
57c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getPlayStatus);
58c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
59c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
60c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
61c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic void btavrcp_get_element_attr_callback(uint8_t num_attr, btrc_media_attr_t *p_attrs) {
62c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    jintArray attrs;
63c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
64c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    ALOGI("%s", __FUNCTION__);
65c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
66c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (!checkCallbackThread()) {
67c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
68c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return;
69c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
70c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    attrs = (jintArray)sCallbackEnv->NewIntArray(num_attr);
71c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (!attrs) {
72c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("Fail to new jintArray for attrs");
73c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
74c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return;
75c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
76c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    sCallbackEnv->SetIntArrayRegion(attrs, 0, num_attr, (jint *)p_attrs);
77c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getElementAttr, (jbyte)num_attr, attrs);
78c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
79c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    sCallbackEnv->DeleteLocalRef(attrs);
80c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
81c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
82c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic void btavrcp_register_notification_callback(btrc_event_id_t event_id, uint32_t param) {
83c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    ALOGI("%s", __FUNCTION__);
84c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
85c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (!checkCallbackThread()) {
86c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
87c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return;
88c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
89c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
90c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_registerNotification,
91c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                                 (jint)event_id, (jint)param);
92c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
93c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
94c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
95c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic btrc_callbacks_t sBluetoothAvrcpCallbacks = {
96c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    sizeof(sBluetoothAvrcpCallbacks),
97c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    btavrcp_get_play_status_callback,
98c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    NULL,
99c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    NULL,
100c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    NULL,
101c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    NULL,
102c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    NULL,
103c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    NULL,
104c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    btavrcp_get_element_attr_callback,
105c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    btavrcp_register_notification_callback
106c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu};
107c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
108c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic void classInitNative(JNIEnv* env, jclass clazz) {
109c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    method_getPlayStatus =
110c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        env->GetMethodID(clazz, "getPlayStatus", "()V");
111c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
112c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    method_getElementAttr =
113c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        env->GetMethodID(clazz, "getElementAttr", "(B[I)V");
114c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
115c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    method_registerNotification =
116c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        env->GetMethodID(clazz, "registerNotification", "(II)V");
117c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
118c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    ALOGI("%s: succeeds", __FUNCTION__);
119c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
120c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
121c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic void initNative(JNIEnv *env, jobject object) {
122c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    const bt_interface_t* btInf;
123c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    bt_status_t status;
124c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
125c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if ( (btInf = getBluetoothInterface()) == NULL) {
126c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("Bluetooth module is not loaded");
127c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return;
128c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
129c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
130c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (sBluetoothAvrcpInterface !=NULL) {
131c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu         ALOGW("Cleaning up Avrcp Interface before initializing...");
132c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu         sBluetoothAvrcpInterface->cleanup();
133c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu         sBluetoothAvrcpInterface = NULL;
134c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
135c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
136c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (mCallbacksObj != NULL) {
137c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu         ALOGW("Cleaning up Avrcp callback object");
138c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu         env->DeleteGlobalRef(mCallbacksObj);
139c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu         mCallbacksObj = NULL;
140c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
141c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
142c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if ( (sBluetoothAvrcpInterface = (btrc_interface_t *)
143c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu          btInf->get_profile_interface(BT_PROFILE_AV_RC_ID)) == NULL) {
144c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("Failed to get Bluetooth Avrcp Interface");
145c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return;
146c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
147c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
148c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if ( (status = sBluetoothAvrcpInterface->init(&sBluetoothAvrcpCallbacks)) !=
149c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu         BT_STATUS_SUCCESS) {
150c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("Failed to initialize Bluetooth Avrcp, status: %d", status);
151c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        sBluetoothAvrcpInterface = NULL;
152c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return;
153c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
154c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
155c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    mCallbacksObj = env->NewGlobalRef(object);
156c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
157c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
158c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic void cleanupNative(JNIEnv *env, jobject object) {
159c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    const bt_interface_t* btInf;
160c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
161c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if ( (btInf = getBluetoothInterface()) == NULL) {
162c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("Bluetooth module is not loaded");
163c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return;
164c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
165c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
166c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (sBluetoothAvrcpInterface !=NULL) {
167c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        sBluetoothAvrcpInterface->cleanup();
168c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        sBluetoothAvrcpInterface = NULL;
169c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
170c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
171c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (mCallbacksObj != NULL) {
172c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        env->DeleteGlobalRef(mCallbacksObj);
173c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mCallbacksObj = NULL;
174c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
175c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
176c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
177c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic jboolean getPlayStatusRspNative(JNIEnv *env, jobject object, jint playStatus,
178c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                                       jint songLen, jint songPos) {
179c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    bt_status_t status;
180c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
181c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
182c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (!sBluetoothAvrcpInterface) return JNI_FALSE;
183c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
184c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if ((status = sBluetoothAvrcpInterface->get_play_status_rsp((btrc_play_status_t)playStatus,
185c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                                            songLen, songPos)) != BT_STATUS_SUCCESS) {
186c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("Failed get_play_status_rsp, status: %d", status);
187c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
188c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
189c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
190c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
191c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
192c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu  static jboolean getElementAttrRspNative(JNIEnv *env, jobject object, jbyte numAttr,
193c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                                          jintArray attrIds, jobjectArray textArray) {
194c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    jint *attr;
195c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    bt_status_t status;
196c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    jstring text;
197c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    int i;
198c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    btrc_element_attr_val_t *pAttrs = NULL;
199c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    const char* textStr;
200c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
201c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (!sBluetoothAvrcpInterface) return JNI_FALSE;
202c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
203c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (numAttr > BTRC_MAX_ELEM_ATTR_SIZE) {
204c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("get_element_attr_rsp: number of attributes exceed maximum");
205c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return JNI_FALSE;
206c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
207c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
208c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    pAttrs = new btrc_element_attr_val_t[numAttr];
209c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (!pAttrs) {
210c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("get_element_attr_rsp: not have enough memeory");
211c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return JNI_FALSE;
212c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
213c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
214c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    attr = env->GetIntArrayElements(attrIds, NULL);
215c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (!attr) {
216c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        delete[] pAttrs;
217c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        jniThrowIOException(env, EINVAL);
218c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return JNI_FALSE;
219c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
220c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
221c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    for (i = 0; i < numAttr; ++i) {
222c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        text = (jstring) env->GetObjectArrayElement(textArray, i);
223c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        textStr = env->GetStringUTFChars(text, NULL);
224c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        if (!textStr) {
225c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            ALOGE("get_element_attr_rsp: GetStringUTFChars return NULL");
226c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            env->DeleteLocalRef(text);
227c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            break;
228c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
229885213461ae72d6db178c95fafc01cde153230dbZhihai Xu
230885213461ae72d6db178c95fafc01cde153230dbZhihai Xu        pAttrs[i].attr_id = attr[i];
231c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        if (strlen(textStr) >= BTRC_MAX_ATTR_STR_LEN) {
232c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            ALOGE("get_element_attr_rsp: string length exceed maximum");
233885213461ae72d6db178c95fafc01cde153230dbZhihai Xu            strncpy((char *)pAttrs[i].text, textStr, BTRC_MAX_ATTR_STR_LEN-1);
234885213461ae72d6db178c95fafc01cde153230dbZhihai Xu            pAttrs[i].text[BTRC_MAX_ATTR_STR_LEN-1] = 0;
235885213461ae72d6db178c95fafc01cde153230dbZhihai Xu        } else {
236885213461ae72d6db178c95fafc01cde153230dbZhihai Xu            strcpy((char *)pAttrs[i].text, textStr);
237c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
238c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        env->ReleaseStringUTFChars(text, textStr);
239c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        env->DeleteLocalRef(text);
240c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
241c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
242c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (i < numAttr) {
243c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        delete[] pAttrs;
244c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        env->ReleaseIntArrayElements(attrIds, attr, 0);
245c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return JNI_FALSE;
246c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
247c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
248c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if ((status = sBluetoothAvrcpInterface->get_element_attr_rsp(numAttr, pAttrs)) !=
249c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        BT_STATUS_SUCCESS) {
250c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("Failed get_element_attr_rsp, status: %d", status);
251c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
252c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
253c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    delete[] pAttrs;
254c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    env->ReleaseIntArrayElements(attrIds, attr, 0);
255c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
256c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
257c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
258c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic jboolean registerNotificationRspPlayStatusNative(JNIEnv *env, jobject object,
259c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                                                        jint type, jint playStatus) {
260c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    bt_status_t status;
261c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    btrc_register_notification_t param;
262c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
263c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
264c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (!sBluetoothAvrcpInterface) return JNI_FALSE;
265c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
266c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    param.play_status = (btrc_play_status_t)playStatus;
267c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if ((status = sBluetoothAvrcpInterface->register_notification_rsp(BTRC_EVT_PLAY_STATUS_CHANGED,
268c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                  (btrc_notification_type_t)type, &param)) != BT_STATUS_SUCCESS) {
269c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("Failed register_notification_rsp play status, status: %d", status);
270c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
271c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
272c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
273c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
274c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
275c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic jboolean registerNotificationRspTrackChangeNative(JNIEnv *env, jobject object,
276c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                                                         jint type, jbyteArray track) {
277c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    bt_status_t status;
278c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    btrc_register_notification_t param;
279c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    jbyte *trk;
280c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    int i;
281c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
282c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
283c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (!sBluetoothAvrcpInterface) return JNI_FALSE;
284c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
285c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    trk = env->GetByteArrayElements(track, NULL);
286c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (!trk) {
287c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        jniThrowIOException(env, EINVAL);
288c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return JNI_FALSE;
289c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
290c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
291c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    for (i = 0; i < BTRC_UID_SIZE; ++i) {
292c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu      param.track[i] = trk[i];
293c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
294c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
295c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if ((status = sBluetoothAvrcpInterface->register_notification_rsp(BTRC_EVT_TRACK_CHANGE,
296c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                  (btrc_notification_type_t)type, &param)) != BT_STATUS_SUCCESS) {
297c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("Failed register_notification_rsp track change, status: %d", status);
298c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
299c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
300c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    env->ReleaseByteArrayElements(track, trk, 0);
301c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
302c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
303c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
304aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xustatic jboolean registerNotificationRspPlayPosNative(JNIEnv *env, jobject object,
305aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                                                        jint type, jint playPos) {
306aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    bt_status_t status;
307aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    btrc_register_notification_t param;
308aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
309aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
310aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    if (!sBluetoothAvrcpInterface) return JNI_FALSE;
311aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
312aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    param.song_pos = (uint32_t)playPos;
313aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    if ((status = sBluetoothAvrcpInterface->register_notification_rsp(BTRC_EVT_PLAY_POS_CHANGED,
314aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                  (btrc_notification_type_t)type, &param)) != BT_STATUS_SUCCESS) {
315aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        ALOGE("Failed register_notification_rsp play position, status: %d", status);
316aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    }
317aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
318aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
319aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu}
320aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
321c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic JNINativeMethod sMethods[] = {
322c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    {"classInitNative", "()V", (void *) classInitNative},
323c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    {"initNative", "()V", (void *) initNative},
324c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    {"cleanupNative", "()V", (void *) cleanupNative},
325c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    {"getPlayStatusRspNative", "(III)Z", (void *) getPlayStatusRspNative},
326c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    {"getElementAttrRspNative", "(B[I[Ljava/lang/String;)Z", (void *) getElementAttrRspNative},
327c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    {"registerNotificationRspPlayStatusNative", "(II)Z",
328c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu     (void *) registerNotificationRspPlayStatusNative},
329c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    {"registerNotificationRspTrackChangeNative", "(I[B)Z",
330c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu     (void *) registerNotificationRspTrackChangeNative},
331aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    {"registerNotificationRspPlayPosNative", "(II)Z",
332aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu     (void *) registerNotificationRspPlayPosNative},
333c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu};
334c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
335c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuint register_com_android_bluetooth_avrcp(JNIEnv* env)
336c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu{
337c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    return jniRegisterNativeMethods(env, "com/android/bluetooth/a2dp/Avrcp",
338c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                                    sMethods, NELEM(sMethods));
339c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
340c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
341c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
342